home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume26 / cook-1.4 / part06 < prev    next >
Encoding:
Text File  |  1993-05-03  |  90.2 KB  |  4,340 lines

  1. Newsgroups: comp.sources.unix
  2. From: pmiller@bmr.gov.au (Peter Miller)
  3. Subject: v26i214: cook-1.4 - a file construction tool (like "make"), Part06/11
  4. Sender: unix-sources-moderator@efficacy.home.vix.com
  5. Approved: WhoAmI@efficacy.home.vix.com
  6.  
  7. Submitted-By: pmiller@bmr.gov.au (Peter Miller)
  8. Posting-Number: Volume 26, Issue 214
  9. Archive-Name: cook-1.4/part06
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 6 (of 11)."
  18. # Contents:  c_incl/cache.c c_incl/main.c c_incl/sniff.c
  19. #   common/arglex.c config cook/expr.c cook/hashline.y
  20. # Wrapped by vixie@efficacy.home.vix.com on Tue May  4 01:36:40 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'c_incl/cache.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'c_incl/cache.c'\"
  24. else
  25. echo shar: Extracting \"'c_incl/cache.c'\" \(12450 characters\)
  26. sed "s/^X//" >'c_incl/cache.c' <<'END_OF_FILE'
  27. X/*
  28. X *    cook - file construction tool
  29. X *    Copyright (C) 1991, 1992, 1993 Peter Miller.
  30. X *    All rights reserved.
  31. X *
  32. X *    This program is free software; you can redistribute it and/or modify
  33. X *    it under the terms of the GNU General Public License as published by
  34. X *    the Free Software Foundation; either version 2 of the License, or
  35. X *    (at your option) any later version.
  36. X *
  37. X *    This program is distributed in the hope that it will be useful,
  38. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  39. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  40. X *    GNU General Public License for more details.
  41. X *
  42. X *    You should have received a copy of the GNU General Public License
  43. X *    along with this program; if not, write to the Free Software
  44. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  45. X *
  46. X * MANIFEST: functions to manipulate include file cache
  47. X */
  48. X
  49. X#include <stdio.h>
  50. X
  51. X#include <arglex.h>
  52. X#include <cache.h>
  53. X#include <error.h>
  54. X#include <mem.h>
  55. X#include <os.h>
  56. X
  57. Xtypedef struct node node;
  58. Xstruct node
  59. X{
  60. X    cache_ty    cache;
  61. X    node        *next;
  62. X};
  63. X
  64. X
  65. Xstatic    node        **hash_table;
  66. Xstatic    str_hash_ty    hash_modulus;
  67. Xstatic    str_hash_ty    hash_cutover;
  68. Xstatic    str_hash_ty    hash_cutover_mask;
  69. Xstatic    str_hash_ty    hash_cutover_split_mask;
  70. Xstatic    str_hash_ty    hash_split;
  71. Xstatic    str_hash_ty    hash_load;
  72. Xstatic    int        need_to_write;
  73. X
  74. X
  75. X/*
  76. X * NAME
  77. X *    cache_initialize - start up cache
  78. X *
  79. X * SYNOPSIS
  80. X *    void cache_initialize(void);
  81. X *
  82. X * DESCRIPTION
  83. X *    The cache_initialize function is used to create the hash table.
  84. X *
  85. X * RETURNS
  86. X *    void
  87. X *
  88. X * CAVEAT
  89. X *    Assumes the str_initialize function has been called already.
  90. X */
  91. X
  92. Xvoid
  93. Xcache_initialize()
  94. X{
  95. X    str_hash_ty    j;
  96. X
  97. X    assert(!hash_modulus);
  98. X    hash_modulus = 1<<8; /* MUST be a power of 2 */
  99. X    hash_cutover = hash_modulus;
  100. X    hash_split = hash_modulus - hash_cutover;
  101. X    hash_cutover_mask = hash_cutover - 1;
  102. X    hash_cutover_split_mask = (hash_cutover * 2) - 1;
  103. X    hash_load = 0;
  104. X    hash_table = (node **)mem_alloc(hash_modulus * sizeof(node*));
  105. X    for (j = 0; j < hash_modulus; ++j)
  106. X        hash_table[j] = 0;
  107. X}
  108. X
  109. X
  110. X/*
  111. X * NAME
  112. X *    split - reduce symbol table load
  113. X *
  114. X * SYNOPSIS
  115. X *    void split(void);
  116. X *
  117. X * DESCRIPTION
  118. X *    The split function is used to split symbols in the bucket indicated by
  119. X *    the split point.  The symbols are split between that bucket and the one
  120. X *    after the current end of the table.
  121. X *
  122. X * RETURNS
  123. X *    void
  124. X *
  125. X * CAVEAT
  126. X *    It is only sensable to do this when the symbol table load exceeds some
  127. X *    reasonable threshold.  A threshold of 80% is suggested.
  128. X */
  129. X
  130. Xstatic void split _((void));
  131. X
  132. Xstatic void
  133. Xsplit()
  134. X{
  135. X    node        *p;
  136. X    node        **ipp;
  137. X    node        *p2;
  138. X    str_hash_ty    index;
  139. X
  140. X    /*
  141. X     * get the list to be split across buckets 
  142. X     */
  143. X    p = hash_table[hash_split];
  144. X    hash_table[hash_split] = 0;
  145. X
  146. X    /*
  147. X     * increase the modulus by one
  148. X     */
  149. X    hash_modulus++;
  150. X    mem_change_size((char **)&hash_table, hash_modulus * sizeof(node*));
  151. X    hash_table[hash_modulus - 1] = 0;
  152. X    hash_split = hash_modulus - hash_cutover;
  153. X    if (hash_split >= hash_cutover)
  154. X    {
  155. X        hash_cutover = hash_modulus;
  156. X        hash_split = 0;
  157. X        hash_cutover_mask = hash_cutover - 1;
  158. X        hash_cutover_split_mask = (hash_cutover * 2) - 1;
  159. X    }
  160. X
  161. X    /*
  162. X     * now redistribute the list elements
  163. X     *
  164. X     * It is important to preserve the order of the links because they can be
  165. X     * push-down stacks, and to simply add them to the head of the list will
  166. X     * reverse the order of the stack!
  167. X     */
  168. X    while (p)
  169. X    {
  170. X        p2 = p;
  171. X        p = p2->next;
  172. X        p2->next = 0;
  173. X
  174. X        index = p2->cache.filename->str_hash & hash_cutover_mask;
  175. X        if (index < hash_split)
  176. X            index = p2->cache.filename->str_hash & hash_cutover_split_mask;
  177. X        for (ipp = &hash_table[index]; *ipp; ipp = &(*ipp)->next)
  178. X            ;
  179. X        *ipp = p2;
  180. X    }
  181. X}
  182. X
  183. X
  184. X/*
  185. X * NAME
  186. X *    cache_search - search for a variable
  187. X *
  188. X * SYNOPSIS
  189. X *    int cache_search(string_ty *filename);
  190. X *
  191. X * DESCRIPTION
  192. X *    The cache_search function is used to search for
  193. X *    a filename in the cache.
  194. X *
  195. X * RETURNS
  196. X *    If the variable has been defined, the function returns a non-zero value
  197. X *    and the value is returned through the 'value' pointer.
  198. X *    If the variable has not been defined, it returns zero,
  199. X *    and 'value' is unaltered.
  200. X *
  201. X * CAVEAT
  202. X *    The value returned from this function, when returned, is allocated
  203. X *    in dynamic memory (it is a copy of the value remembered by this module).
  204. X *    It is the responsibility of the caller to free it when finished with,
  205. X *    by a wl_free() call.
  206. X */
  207. X
  208. Xcache_ty *
  209. Xcache_search(filename)
  210. X    string_ty    *filename;
  211. X{
  212. X    str_hash_ty    index;
  213. X    node        *p;
  214. X
  215. X    /*
  216. X     * work out what index in must have
  217. X     */
  218. X    assert(hash_modulus);
  219. X    index = filename->str_hash & hash_cutover_mask;
  220. X    if (index < hash_split)
  221. X        index = filename->str_hash & hash_cutover_split_mask;
  222. X
  223. X    /*
  224. X     * search down that hash chain
  225. X     */
  226. X    for (p = hash_table[index]; p; p = p->next)
  227. X    {
  228. X        if (str_equal(filename, p->cache.filename))
  229. X            return &p->cache;
  230. X    }
  231. X
  232. X    /*
  233. X     * not there, so make one
  234. X     */
  235. X    p = (node *)mem_alloc_clear(sizeof(node));
  236. X    p->next = hash_table[index];
  237. X    hash_table[index] = p;
  238. X    p->cache.filename = str_copy(filename);
  239. X
  240. X    /*
  241. X     * split if the load gets too high
  242. X     */
  243. X    hash_load++;
  244. X    while (hash_load * 10 >= hash_modulus * 8)
  245. X        split();
  246. X
  247. X    /*
  248. X     * return new cache entry
  249. X     */
  250. X    return &p->cache;
  251. X}
  252. X
  253. X
  254. X/*
  255. X * NAME
  256. X *    build_filename - for cache file
  257. X *
  258. X * SYNOPSIS
  259. X *    void build_filename(char *buffer);
  260. X *
  261. X * DESCRIPTION
  262. X *    The build_filename function is used to build
  263. X *    the name of the cache file.
  264. X *
  265. X * ARGUMENTS
  266. X *    buffer    - where to put the file name
  267. X *
  268. X * CAVEATS
  269. X *    The cache file is in the current directory.
  270. X */
  271. X
  272. Xstatic void build_filename _((char *));
  273. X
  274. Xstatic void
  275. Xbuild_filename(buffer)
  276. X    char        *buffer;
  277. X{
  278. X    sprintf(buffer, ".%src", progname);
  279. X}
  280. X
  281. X
  282. X/*
  283. X * NAME
  284. X *    fread_sane - a saner version of fread
  285. X *
  286. X * SYNOPSIS
  287. X *    int fread_sane(FILE *fp, void *buf, size_t buflen);
  288. X *
  289. X * DESCRIPTION
  290. X *    The fread_sane function is used to read from a standard stream.
  291. X *
  292. X * ARGUMENTS
  293. X *    fp    - the stream to read from
  294. X *    buf    - where to place the bytes read
  295. X *    buflen    - number of bytes to read
  296. X *
  297. X * RETURNS
  298. X *    0 on no error, -1 on any error
  299. X *
  300. X * CAVEATS
  301. X *    This version considers it to be an error if end-of-file is reached.
  302. X */
  303. X
  304. Xstatic int fread_sane _((FILE *, void *, size_t));
  305. X
  306. Xstatic int
  307. Xfread_sane(fp, buf, buflen)
  308. X    FILE        *fp;
  309. X    void        *buf;
  310. X    size_t        buflen;
  311. X{
  312. X    if (fread(buf, 1, buflen, fp) != buflen)
  313. X        return -1;
  314. X    return 0;
  315. X}
  316. X
  317. X
  318. X/*
  319. X * NAME
  320. X *    cache_read_string - read a string from a file
  321. X *
  322. X * SYNOPSIS
  323. X *    string_ty *cache_read_string(FILE *fp));
  324. X *
  325. X * DESCRIPTION
  326. X *    The cache_read_string function is used to read a string
  327. X *    from a file.
  328. X *
  329. X * ARGUMENTS
  330. X *    fp    - file to read string from
  331. X *
  332. X * RETURNS
  333. X *    pointer to string if successful, 0 if not.
  334. X *
  335. X * CAVEATS
  336. X *    Must be symmetric with cache_write string below.
  337. X */
  338. X
  339. Xstatic string_ty *cache_read_string _((FILE *));
  340. X
  341. Xstatic string_ty *
  342. Xcache_read_string(fp)
  343. X    FILE        *fp;
  344. X{
  345. X    static size_t    buflen;
  346. X    static char    *buf;
  347. X    size_t        len;
  348. X
  349. X    if (fread_sane(fp, &len, sizeof(len)))
  350. X        return 0;
  351. X    if (len > buflen)
  352. X    {
  353. X        buflen = (len + 0xFF) & ~0xFF;
  354. X        if (!buf)
  355. X            buf = mem_alloc(buflen);
  356. X        else
  357. X            mem_change_size(&buf, buflen);
  358. X    }
  359. X    if (fread_sane(fp, buf, len))
  360. X        return 0;
  361. X    return str_n_from_c(buf, len);
  362. X}
  363. X
  364. X
  365. X/*
  366. X * NAME
  367. X *    cache_read_item - read a cache item from a file
  368. X *
  369. X * SYNOPSIS
  370. X *    int cache_read_item(FILE *fp);
  371. X *
  372. X * DESCRIPTION
  373. X *    The cache_read_item function is used to read an item from
  374. X *    the cache file and installit into the cache.
  375. X *
  376. X * ARGUMENTS
  377. X *    fp    - the file to read the item from
  378. X *
  379. X * RETURNS
  380. X *    0 in success, -1 on any error
  381. X *
  382. X * CAVEATS
  383. X *    Must be symmetric with cache_write_item below.
  384. X */
  385. X
  386. Xstatic int cache_read_item _((FILE *));
  387. X
  388. Xstatic int
  389. Xcache_read_item(fp)
  390. X    FILE        *fp;
  391. X{
  392. X    string_ty    *s;
  393. X    cache_ty    *cp;
  394. X    size_t        nitems;
  395. X    size_t        j;
  396. X
  397. X    s = cache_read_string(fp);
  398. X    if (!s)
  399. X        return -1;
  400. X    cp = cache_search(s);
  401. X    assert(cp);
  402. X    if (fread_sane(fp, &cp->st, sizeof(cp->st)))
  403. X        return -1;
  404. X    if (fread_sane(fp, &nitems, sizeof(nitems)))
  405. X        return -1;
  406. X    for (j = 0; j < nitems; ++j)
  407. X    {
  408. X        s = cache_read_string(fp);
  409. X        if (!s)
  410. X            return -1;
  411. X        wl_append_unique(&cp->ingredients, s);
  412. X    }
  413. X    return 0;
  414. X}
  415. X
  416. X
  417. X/*
  418. X * NAME
  419. X *    cache_read - read the cache file into the cache
  420. X *
  421. X * SYNOPSIS
  422. X *    void cache_read(void);
  423. X *
  424. X * DESCRIPTION
  425. X *    The cache_read function is used to read the cache file into the cache.
  426. X *
  427. X * CAVEATS
  428. X *    If the cache file is not there, it is as iff the cache file
  429. X *    contained an image of an empty cache.  I.e. nothing happens,
  430. X *    but it is not an error.
  431. X */
  432. X
  433. Xvoid
  434. Xcache_read()
  435. X{
  436. X    str_hash_ty    nitems;
  437. X    str_hash_ty    j;
  438. X    FILE        *fp;
  439. X    char        filename[256];
  440. X
  441. X    /*
  442. X     * open the cache file.
  443. X     * if it's not there, quietly slink away
  444. X     */
  445. X    build_filename(filename);
  446. X    if (!os_exists(filename))
  447. X        return;
  448. X    fp = fopen(filename, "rb");
  449. X    if (!fp)
  450. X    {
  451. X        bomb:
  452. X        nfatal("%s", filename);
  453. X    }
  454. X
  455. X    /*
  456. X     * get the number of entries in the file
  457. X     */
  458. X    if (fread_sane(fp, &nitems, sizeof(nitems)))
  459. X        goto bomb;
  460. X
  461. X    /*
  462. X     * read each entry in the file
  463. X     */
  464. X    for (j = 0; j < nitems; ++j)
  465. X    {
  466. X        if (cache_read_item(fp))
  467. X            goto bomb;
  468. X    }
  469. X
  470. X    /*
  471. X     * all done
  472. X     */
  473. X    fclose(fp);
  474. X}
  475. X
  476. X
  477. X/*
  478. X * NAME
  479. X *    fwrite_sane - a saner version of fwrite
  480. X *
  481. X * SYNOPSIS
  482. X *    int fwrite_sane(FILE *fp, void *buf, size_t buflen);
  483. X *
  484. X * DESCRIPTION
  485. X *    The fwrite_sane function is used to write data to a file.
  486. X *
  487. X * ARGUMENTS
  488. X *    fp    - file to write to
  489. X *    buf    - pointer to data to write
  490. X *    buflen    - number of bytes in data
  491. X *
  492. X * RETURNS
  493. X *    0 on success, -1 on any error
  494. X */
  495. X
  496. Xstatic int fwrite_sane _((FILE *, void *, size_t));
  497. X
  498. Xstatic int
  499. Xfwrite_sane(fp, buf, buflen)
  500. X    FILE        *fp;
  501. X    void        *buf;
  502. X    size_t        buflen;
  503. X{
  504. X    if (fwrite(buf, 1, buflen, fp) != buflen)
  505. X        return -1;
  506. X    return 0;
  507. X}
  508. X
  509. X
  510. X/*
  511. X * NAME
  512. X *    cache_write_string - write a string to a file
  513. X *
  514. X * SYNOPSIS
  515. X *    int cache_write_string(FILE *fp, string_ty *s);
  516. X *
  517. X * DESCRIPTION
  518. X *    The cache_write_string function is used to write a string to a file.
  519. X *
  520. X * ARGUMENTS
  521. X *    fp    - file to write
  522. X *    s    - string to be written
  523. X *
  524. X * RETURNS
  525. X *    0 on success, -1 on any error
  526. X *
  527. X * CAVEATS
  528. X *    Must be symmetric with cache_read_string above.
  529. X */
  530. X
  531. Xstatic int cache_write_string _((FILE *, string_ty *));
  532. X
  533. Xstatic int
  534. Xcache_write_string(fp, s)
  535. X    FILE        *fp;
  536. X    string_ty    *s;
  537. X{
  538. X    if (fwrite_sane(fp, &s->str_length, sizeof(s->str_length)))
  539. X        return -1;
  540. X    if (fwrite_sane(fp, s->str_text, s->str_length))
  541. X        return -1;
  542. X    return 0;
  543. X}
  544. X
  545. X
  546. X/*
  547. X * NAME
  548. X *    cache_write_item - write cache item to cache file
  549. X *
  550. X * SYNOPSIS
  551. X *    int cache_write_item(FILE *fp, cache_ty *cp);
  552. X *
  553. X * DESCRIPTION
  554. X *    The cache_write_item function is used to write a cache
  555. X *    item to a cache  file.
  556. X *
  557. X * ARGUMENTS
  558. X *    fp    - file to write
  559. X *    cp    - pointer to cache item to write
  560. X *
  561. X * RETURNS
  562. X *    0 on success, -1 on any error
  563. X *
  564. X * CAVEATS
  565. X *    Must be symmetric with cache_read_item above.
  566. X */
  567. X
  568. Xstatic int cache_write_item _((FILE *, cache_ty *));
  569. X
  570. Xstatic int
  571. Xcache_write_item(fp, cp)
  572. X    FILE        *fp;
  573. X    cache_ty    *cp;
  574. X{
  575. X    size_t        j;
  576. X
  577. X    if (cache_write_string(fp, cp->filename))
  578. X        return -1;
  579. X    if (fwrite_sane(fp, &cp->st, sizeof(cp->st)))
  580. X        return -1;
  581. X    if (fwrite_sane(fp, &cp->ingredients.wl_nwords, sizeof(cp->ingredients.wl_nwords)))
  582. X        return -1;
  583. X    for (j = 0; j < cp->ingredients.wl_nwords; ++j)
  584. X        if (cache_write_string(fp, cp->ingredients.wl_word[j]))
  585. X            return -1;
  586. X    return 0;
  587. X}
  588. X
  589. X
  590. X/*
  591. X * NAME
  592. X *    cache_write - write cache to file
  593. X *
  594. X * SYNOPSIS
  595. X *    void cache_write(void);
  596. X *
  597. X * DESCRIPTION
  598. X *    The cache_write function is used to write the memory image
  599. X *    of the cache into a disk file.
  600. X *
  601. X * CAVEATS
  602. X *    The cache file is in the current directory.
  603. X */
  604. X
  605. Xvoid
  606. Xcache_write()
  607. X{
  608. X    node        *p;
  609. X    FILE        *fp;
  610. X    char        filename[256];
  611. X    str_hash_ty    index;
  612. X
  613. X    /*
  614. X     * don't change the file if we don't have to
  615. X     */
  616. X    if (!need_to_write)
  617. X        return;
  618. X    need_to_write = 0;
  619. X
  620. X    /*
  621. X     * open the cache file
  622. X     */
  623. X    build_filename(filename);
  624. X    fp = fopen(filename, "wb");
  625. X    if (!fp)
  626. X    {
  627. X        bomb:
  628. X        nfatal("%s", filename);
  629. X    }
  630. X
  631. X    /*
  632. X     * write the number of entries to the file
  633. X     */
  634. X    if (fwrite_sane(fp, &hash_load, sizeof(hash_load)))
  635. X        goto bomb;
  636. X
  637. X    /*
  638. X     * write each cache entry to the file
  639. X     */
  640. X    for (index = 0; index < hash_modulus; ++index)
  641. X    {
  642. X        for (p = hash_table[index]; p; p = p->next)
  643. X        {
  644. X            if (cache_write_item(fp, &p->cache))
  645. X                goto bomb;
  646. X        }
  647. X    }
  648. X
  649. X    /*
  650. X     * close the cache file
  651. X     */
  652. X    if (fclose(fp))
  653. X        goto bomb;
  654. X}
  655. X
  656. X
  657. X/*
  658. X * NAME
  659. X *    cache_update_notify - cache has changed
  660. X *
  661. X * SYNOPSIS
  662. X *    void cache_update_nitify(void);
  663. X *
  664. X * DESCRIPTION
  665. X *    The cache_update_notify function is called whenever the contents
  666. X *    of the cache is changed.  This notifies the cache_write function
  667. X *    that it needs to rewrite the cache file.
  668. X */
  669. X
  670. Xvoid
  671. Xcache_update_notify()
  672. X{
  673. X    need_to_write = 1;
  674. X}
  675. END_OF_FILE
  676. if test 12450 -ne `wc -c <'c_incl/cache.c'`; then
  677.     echo shar: \"'c_incl/cache.c'\" unpacked with wrong size!
  678. fi
  679. # end of 'c_incl/cache.c'
  680. fi
  681. if test -f 'c_incl/main.c' -a "${1}" != "-c" ; then 
  682.   echo shar: Will not clobber existing file \"'c_incl/main.c'\"
  683. else
  684. echo shar: Extracting \"'c_incl/main.c'\" \(11963 characters\)
  685. sed "s/^X//" >'c_incl/main.c' <<'END_OF_FILE'
  686. X/*
  687. X *    cook - file construction tool
  688. X *    Copyright (C) 1991, 1992, 1993 Peter Miller.
  689. X *    All rights reserved.
  690. X *
  691. X *    This program is free software; you can redistribute it and/or modify
  692. X *    it under the terms of the GNU General Public License as published by
  693. X *    the Free Software Foundation; either version 2 of the License, or
  694. X *    (at your option) any later version.
  695. X *
  696. X *    This program is distributed in the hope that it will be useful,
  697. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  698. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  699. X *    GNU General Public License for more details.
  700. X *
  701. X *    You should have received a copy of the GNU General Public License
  702. X *    along with this program; if not, write to the Free Software
  703. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  704. X *
  705. X * MANIFEST: operating system entry point, and command line argument parsing
  706. X */
  707. X
  708. X#include <stddef.h>
  709. X#include <stdio.h>
  710. X#include <string.h>
  711. X#include <stdlib.h>
  712. X
  713. X#include <arglex.h>
  714. X#include <cache.h>
  715. X#include <error.h>
  716. X#include <help.h>
  717. X#include <main.h>
  718. X#include <sniff.h>
  719. X#include <str.h>
  720. X#include <trace.h>
  721. X#include <version.h>
  722. X
  723. X
  724. Xstatic void usage _((void));
  725. X
  726. Xstatic void
  727. Xusage()
  728. X{
  729. X    fprintf(stderr, "usage: %s [ <option>... ] <filename>\n", progname);
  730. X    fprintf(stderr, "       %s -Help\n", progname);
  731. X    fprintf(stderr, "       %s -VERsion\n", progname);
  732. X    exit(1);
  733. X}
  734. X
  735. X
  736. Xstatic void c_incl_help _((void));
  737. X
  738. Xstatic void
  739. Xc_incl_help()
  740. X{
  741. X    static char *text[] =
  742. X    {
  743. X"NAME",
  744. X"    %s - determine dependencies",
  745. X"",
  746. X"SYNOPSIS",
  747. X"    %s [ <option>... ] <filename>",
  748. X"    %s -Help",
  749. X"    %s -VERSion",
  750. X"",
  751. X"DESCRIPTION",
  752. X"    The %s program is used to traverse source files",
  753. X"    looking for include dependencies suitable for",
  754. X"    [collect]ion by cook.",
  755. X"",
  756. X"    Several input languages are supported, see the options",
  757. X"    list for details.",
  758. X"",
  759. X"OPTIONS",
  760. X"    The following options are understood.",
  761. X"",
  762. X"    -C",
  763. X"        The source file is a C source file.  It is",
  764. X"        assumed that it will have the dependencies",
  765. X"        resolved by the cpp(1) command.  The same include",
  766. X"        semantics as the cpp(1) command will be employed.",
  767. X"        This is the default.",
  768. X"",
  769. X"    -Roff",
  770. X"        The source file is a *roff source file.  It is",
  771. X"        assumed that it will have the dependencies",
  772. X"        resolved by the roffpp(1) command.  The same",
  773. X"        include semantics as the roffpp(1) command will",
  774. X"        be employed.",
  775. X"",
  776. X"    -Verbose",
  777. X"        Tell what is happening.",
  778. X"",
  779. X"    -I<path>",
  780. X"        Specify include path, a la cc(1).",
  781. X"",
  782. X"    -Absent_Local_Ignore",
  783. X"        For files included using a #include",
  784. X"        ''filename.h'' directive, ignore the file if it",
  785. X"        cannot be found.",
  786. X"",
  787. X"    -Absent_Local_Mention",
  788. X"        For files included using a #include",
  789. X"        ''filename.h'' directive, print the file name",
  790. X"        even if the file cannot be found.  This is the",
  791. X"        default (it probably needs to be built).",
  792. X"",
  793. X"    -Absent_Local_Error",
  794. X"        For files included using a #include",
  795. X"        ''filename.h'' directive, print a fatal error if",
  796. X"        the file cannot be found.",
  797. X"",
  798. X"    -Absent_System_Ignore",
  799. X"        For files included with a #include <filename.h>",
  800. X"        directive, ignore the file if it cannot be found.",
  801. X"        This is the default (it was probably ifdef'ed",
  802. X"        out).",
  803. X"",
  804. X"    -Absent_System_Mention",
  805. X"        For files included with a #include <filename.h>",
  806. X"        directive, print the file name even if the file",
  807. X"        cannot be found.",
  808. X"",
  809. X"    -Absent_System_Error",
  810. X"        For files included with a #include <filename.h>",
  811. X"        directive, print a fatal error if the file cannot",
  812. X"        be found.",
  813. X"",
  814. X"    -Absent_Program_Ignore",
  815. X"        If the file named on the command line cannot be",
  816. X"        found, behave as if the file were found, but was",
  817. X"        empty.",
  818. X"",
  819. X"    -Absent_Program_Error",
  820. X"        If the file named on the command line cannot be",
  821. X"        found, print a fatal error message.  This is the",
  822. X"        default.",
  823. X"",
  824. X"    -Help",
  825. X"        Give information on how to use %s.",
  826. X"",
  827. X"    -VERSion",
  828. X"        Tell what version of %s is being run.",
  829. X"",
  830. X"    -No_System",
  831. X"        Do not search the /usr/include directory.  By",
  832. X"        default this is searched last.",
  833. X"",
  834. X"    -No_Cache",
  835. X"        This option may be used to turn caching off.",
  836. X"",
  837. X"    Any other options will generate an error.",
  838. X"",
  839. X"    All options may be abbreviated; the abbreviation is",
  840. X"    documented as the upper case letters, all lower case",
  841. X"    letters and underscores (_) are optional.  You must use",
  842. X"    consecutive sequences of optional letters.",
  843. X"",
  844. X"    All options are case insensitive, you may type them in",
  845. X"    upper case or lower case or a combination of both, case",
  846. X"    is not important.",
  847. X"",
  848. X"    For example: the arguments \"-help\", \"-HEL\" and \"-h\" are",
  849. X"    all interpreted to mean the -Help option.  The argument",
  850. X"    \"-hlp\" will not be understood, because consecutive",
  851. X"    optional characters were not supplied.",
  852. X"",
  853. X"    Options and other command line arguments may be mixed",
  854. X"    arbitrarily on the command line.",
  855. X"",
  856. X"    The GNU long option names are understood.  Since all",
  857. X"    option names for %s are long, this means ignoring the",
  858. X"    extra leading '-'.  The \"--option=value\" convention is",
  859. X"    also understood.",
  860. X"",
  861. X"CACHING",
  862. X"    The caching mechanism use by the %s program caches",
  863. X"    the results of searching files for include files (in a",
  864. X"    file called .%src in the current directory).  The",
  865. X"    cache is only refreshed when a file changes.",
  866. X"",
  867. X"    The use of this cache has been shown to dramatically",
  868. X"    increase the performance of the %s program.",
  869. X"    Typically, only a small proportions files in a project",
  870. X"    change between builds, resulting in a very high cache hit",
  871. X"    rate.",
  872. X"",
  873. X"    When using caching, always use the same command line",
  874. X"    options, otherwise weird and wonderful things will",
  875. X"    happen.",
  876. X"",
  877. X"    The .%src file is a binary file.  If you wish to",
  878. X"    rebuild the cache, simply delete this file with the rm(1)",
  879. X"    command.  Being a binary file, the .%src file is not",
  880. X"    portable across machines or operating systems, so you",
  881. X"    will need to delete it when you move your sources.  It is",
  882. X"    a binary file for performance.",
  883. X"",
  884. X"EXIT STATUS",
  885. X"    The %s command will exit with a status of 1 on any",
  886. X"    error.  The %s command will only exit with a status",
  887. X"    of 0 if there are no errors.",
  888. X"",
  889. X"COPYRIGHT",
  890. X"    %C",
  891. X"",
  892. X"AUTHOR",
  893. X"    %A",
  894. X    };
  895. X
  896. X    trace(("c_incl_help()\n{\n"/*}*/));
  897. X    help(text, SIZEOF(text), usage);
  898. X    trace((/*{*/"}\n"));
  899. X}
  900. X
  901. X
  902. Xenum
  903. X{
  904. X    arglex_token_absent_local_error,
  905. X    arglex_token_absent_local_ignore,
  906. X    arglex_token_absent_local_mention,
  907. X    arglex_token_absent_program_error,
  908. X    arglex_token_absent_program_ignore,
  909. X    arglex_token_absent_system_error,
  910. X    arglex_token_absent_system_ignore,
  911. X    arglex_token_absent_system_mention,
  912. X    arglex_token_include,
  913. X    arglex_token_no_cache,
  914. X    arglex_token_no_system,
  915. X    arglex_token_lang_c,
  916. X    arglex_token_lang_roff,
  917. X    arglex_token_verbose
  918. X};
  919. X
  920. Xstatic    arglex_table_ty    argtab[] =
  921. X{
  922. X    {
  923. X        "-Absent",
  924. X        (arglex_token_ty)arglex_token_absent_local_ignore,
  925. X    },
  926. X    {
  927. X        "-Absent_Local_Error",
  928. X        (arglex_token_ty)arglex_token_absent_local_error,
  929. X    },
  930. X    {
  931. X        "-Absent_Local_Ignore",
  932. X        (arglex_token_ty)arglex_token_absent_local_ignore,
  933. X    },
  934. X    {
  935. X        "-Absent_Local_Mention",
  936. X        (arglex_token_ty)arglex_token_absent_local_mention,
  937. X    },
  938. X    {
  939. X        "-Absent_Program_Error",
  940. X        (arglex_token_ty)arglex_token_absent_program_error,
  941. X    },
  942. X    {
  943. X        "-Absent_Program_Ignore",
  944. X        (arglex_token_ty)arglex_token_absent_program_ignore,
  945. X    },
  946. X    {
  947. X        "-Absent_System_Error",
  948. X        (arglex_token_ty)arglex_token_absent_system_error,
  949. X    },
  950. X    {
  951. X        "-Absent_System_Ignore",
  952. X        (arglex_token_ty)arglex_token_absent_system_ignore,
  953. X    },
  954. X    {
  955. X        "-Absent_System_Mention",
  956. X        (arglex_token_ty)arglex_token_absent_system_mention,
  957. X    },
  958. X    {
  959. X        "-C",
  960. X        (arglex_token_ty)arglex_token_lang_c,
  961. X    },
  962. X    {
  963. X        "-Empty_If_Absent",
  964. X        (arglex_token_ty)arglex_token_absent_program_ignore,
  965. X    },
  966. X    {
  967. X        "-\\I*",
  968. X        (arglex_token_ty)arglex_token_include,
  969. X    },
  970. X    {
  971. X        "-Include",
  972. X        (arglex_token_ty)arglex_token_include,
  973. X    },
  974. X    {
  975. X        "-No_Cache",
  976. X        (arglex_token_ty)arglex_token_no_cache,
  977. X    },
  978. X    {
  979. X        "-No_System",
  980. X        (arglex_token_ty)arglex_token_no_system,
  981. X    },
  982. X    {
  983. X        "-Roff",
  984. X        (arglex_token_ty)arglex_token_lang_roff,
  985. X    },
  986. X    {
  987. X        "-System_absent",
  988. X        (arglex_token_ty)arglex_token_absent_system_ignore,
  989. X    },
  990. X    {
  991. X        "-Verbose",
  992. X        (arglex_token_ty)arglex_token_verbose,
  993. X    },
  994. X
  995. X    /* end marker */
  996. X    { 0, (arglex_token_ty)0, },
  997. X};
  998. X
  999. X
  1000. Xint main _((int, char **));
  1001. X
  1002. Xint
  1003. Xmain(argc, argv)
  1004. X    int        argc;
  1005. X    char        **argv;
  1006. X{
  1007. X    char        *source;
  1008. X    int        no_system;
  1009. X    int        no_cache;
  1010. X    sniff_ty    *language;
  1011. X
  1012. X    arglex_init(argc, argv, argtab);
  1013. X    str_initialize();
  1014. X    cache_initialize();
  1015. X    switch (arglex())
  1016. X    {
  1017. X    case arglex_token_help:
  1018. X        c_incl_help();
  1019. X        exit(0);
  1020. X
  1021. X    case arglex_token_version:
  1022. X        version();
  1023. X        exit(0);
  1024. X
  1025. X    default:
  1026. X        break;
  1027. X    }
  1028. X
  1029. X    source = 0;
  1030. X    no_system = 0;
  1031. X    no_cache = 0;
  1032. X    language = 0;
  1033. X    option.o_absent_local = -1;
  1034. X    option.o_absent_system = -1;
  1035. X    option.o_absent_program = -1;
  1036. X    while (arglex_token != arglex_token_eoln)
  1037. X    {
  1038. X        switch(arglex_token)
  1039. X        {
  1040. X        default:
  1041. X            error
  1042. X            (
  1043. X                "misplaced \"%s\" command line argument",
  1044. X                arglex_value.alv_string
  1045. X            );
  1046. X            usage();
  1047. X
  1048. X        case arglex_token_string:
  1049. X            if (source)
  1050. X                fatal("too many filenames specified");
  1051. X            source = arglex_value.alv_string;
  1052. X            break;
  1053. X
  1054. X        case arglex_token_verbose:
  1055. X            if (option.o_verbose)
  1056. X            {
  1057. X                duplicate:
  1058. X                fatal
  1059. X                (
  1060. X                    "duplicate \"%s\" option",
  1061. X                    arglex_value.alv_string
  1062. X                );
  1063. X            }
  1064. X            ++option.o_verbose;
  1065. X            break;
  1066. X
  1067. X        case arglex_token_absent_local_ignore:
  1068. X            if (option.o_absent_local != -1)
  1069. X                goto duplicate;
  1070. X            option.o_absent_local = absent_ignore;
  1071. X            break;
  1072. X
  1073. X        case arglex_token_absent_local_mention:
  1074. X            if (option.o_absent_local != -1)
  1075. X                goto duplicate;
  1076. X            option.o_absent_local = absent_mention;
  1077. X            break;
  1078. X
  1079. X        case arglex_token_absent_local_error:
  1080. X            if (option.o_absent_local != -1)
  1081. X                goto duplicate;
  1082. X            option.o_absent_local = absent_error;
  1083. X            break;
  1084. X
  1085. X        case arglex_token_absent_system_ignore:
  1086. X            if (option.o_absent_system != -1)
  1087. X                goto duplicate;
  1088. X            option.o_absent_system = absent_ignore;
  1089. X            break;
  1090. X
  1091. X        case arglex_token_absent_system_mention:
  1092. X            if (option.o_absent_system != -1)
  1093. X                goto duplicate;
  1094. X            option.o_absent_system = absent_mention;
  1095. X            break;
  1096. X
  1097. X        case arglex_token_absent_system_error:
  1098. X            if (option.o_absent_system != -1)
  1099. X                goto duplicate;
  1100. X            option.o_absent_system = absent_error;
  1101. X            break;
  1102. X
  1103. X        case arglex_token_absent_program_ignore:
  1104. X            if (option.o_absent_program != -1)
  1105. X                goto duplicate;
  1106. X            option.o_absent_program = absent_ignore;
  1107. X            break;
  1108. X
  1109. X        case arglex_token_absent_program_error:
  1110. X            if (option.o_absent_program != -1)
  1111. X                goto duplicate;
  1112. X            option.o_absent_program = absent_error;
  1113. X            break;
  1114. X
  1115. X        case arglex_token_include:
  1116. X            if (arglex() != arglex_token_string)
  1117. X                fatal("-Include requires a string argument");
  1118. X            sniff_include(arglex_value.alv_string);
  1119. X            break;
  1120. X
  1121. X        case arglex_token_no_system:
  1122. X            if (no_system)
  1123. X                goto duplicate;
  1124. X            no_system++;
  1125. X            break;
  1126. X
  1127. X        case arglex_token_no_cache:
  1128. X            if (no_cache)
  1129. X                goto duplicate;
  1130. X            no_cache++;
  1131. X            break;
  1132. X
  1133. X        case arglex_token_lang_c:
  1134. X            if (language)
  1135. X                goto duplicate;
  1136. X            language = &lang_c;
  1137. X            break;
  1138. X
  1139. X        case arglex_token_lang_roff:
  1140. X            if (language)
  1141. X                goto duplicate;
  1142. X            language = &lang_roff;
  1143. X            break;
  1144. X
  1145. X#ifdef DEBUG
  1146. X        case arglex_token_tracing:
  1147. X            if (arglex() != arglex_token_string)
  1148. X                fatal("-TRACIng requires one or more string arguments");
  1149. X            for (;;)
  1150. X            {
  1151. X                trace_enable(arglex_value.alv_string);
  1152. X                if (arglex() != arglex_token_string)
  1153. X                    break;
  1154. X            }
  1155. X            continue;
  1156. X#endif
  1157. X        }
  1158. X        arglex();
  1159. X    }
  1160. X    if (option.o_absent_local == -1)
  1161. X        option.o_absent_local = absent_mention;
  1162. X    if (option.o_absent_system == -1)
  1163. X        option.o_absent_system = absent_ignore;
  1164. X    if (option.o_absent_program == -1)
  1165. X        option.o_absent_program = absent_error;
  1166. X    if (!source)
  1167. X        fatal("no input file specified");
  1168. X
  1169. X    /*
  1170. X     * set the language to be used
  1171. X     */
  1172. X    if (!language)
  1173. X        language = &lang_c;
  1174. X    sniff_language(language);
  1175. X
  1176. X    /*
  1177. X     * apply any default or suffix search rules
  1178. X     * or anything else defined by the language
  1179. X     */
  1180. X    if (!no_system)
  1181. X        sniff_prepare();
  1182. X
  1183. X    /*
  1184. X     * read and analyze the file
  1185. X     */
  1186. X    if (!no_cache)
  1187. X        cache_read();
  1188. X    sniff(source);
  1189. X    if (!no_cache)
  1190. X        cache_write();
  1191. X    exit(0);
  1192. X    return 0;
  1193. X}
  1194. END_OF_FILE
  1195. if test 11963 -ne `wc -c <'c_incl/main.c'`; then
  1196.     echo shar: \"'c_incl/main.c'\" unpacked with wrong size!
  1197. fi
  1198. # end of 'c_incl/main.c'
  1199. fi
  1200. if test -f 'c_incl/sniff.c' -a "${1}" != "-c" ; then 
  1201.   echo shar: Will not clobber existing file \"'c_incl/sniff.c'\"
  1202. else
  1203. echo shar: Extracting \"'c_incl/sniff.c'\" \(11352 characters\)
  1204. sed "s/^X//" >'c_incl/sniff.c' <<'END_OF_FILE'
  1205. X/*
  1206. X *    cook - file construction tool
  1207. X *    Copyright (C) 1991, 1992, 1993 Peter Miller.
  1208. X *    All rights reserved.
  1209. X *
  1210. X *    This program is free software; you can redistribute it and/or modify
  1211. X *    it under the terms of the GNU General Public License as published by
  1212. X *    the Free Software Foundation; either version 2 of the License, or
  1213. X *    (at your option) any later version.
  1214. X *
  1215. X *    This program is distributed in the hope that it will be useful,
  1216. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  1217. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1218. X *    GNU General Public License for more details.
  1219. X *
  1220. X *    You should have received a copy of the GNU General Public License
  1221. X *    along with this program; if not, write to the Free Software
  1222. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1223. X *
  1224. X * MANIFEST: functions to scan source files looking for include files
  1225. X */
  1226. X
  1227. X#include <stddef.h>
  1228. X#include <stdio.h>
  1229. X#include <string.h>
  1230. X#include <errno.h>
  1231. X
  1232. X#include <cache.h>
  1233. X#include <error.h>
  1234. X#include <mem.h>
  1235. X#include <os.h>
  1236. X#include <sniff.h>
  1237. X#include <word.h>
  1238. X#include <trace.h>
  1239. X
  1240. Xoption_ty option;
  1241. X
  1242. Xstatic    wlist    srl;
  1243. Xstatic    wlist    visited;
  1244. Xstatic    sniff_ty    *lang;
  1245. X
  1246. X
  1247. Xvoid
  1248. Xsniff_language(lp)
  1249. X    sniff_ty    *lp;
  1250. X{
  1251. X    trace(("sniff_language(lp = %08lX)\n{\n"/*}*/, lp));
  1252. X    assert(lp);
  1253. X    lang = lp;
  1254. X    trace((/*{*/"}\n"));
  1255. X}
  1256. X
  1257. X
  1258. X/*
  1259. X * NAME
  1260. X *    sniff_include
  1261. X *
  1262. X * SYNOPSIS
  1263. X *    void sniff_include(string_ty *path);
  1264. X *
  1265. X * DESCRIPTION
  1266. X *    The sniff_include function is used to add to
  1267. X *    the standard include paths.
  1268. X *
  1269. X * ARGUMENTS
  1270. X *    path    - path to add
  1271. X */
  1272. X
  1273. Xvoid
  1274. Xsniff_include(path)
  1275. X    char        *path;
  1276. X{
  1277. X    string_ty    *s;
  1278. X
  1279. X    assert(path);
  1280. X    trace(("sniff_include(path = \"%s\")\n{\n"/*}*/, path));
  1281. X    s = str_from_c(path);
  1282. X    wl_append_unique(&srl, s);
  1283. X    str_free(s);
  1284. X    trace((/*{*/"}\n"));
  1285. X}
  1286. X
  1287. X
  1288. Xlong
  1289. Xsniff_include_count()
  1290. X{
  1291. X    trace(("sniff_include_count()\n{\n"/*}*/));
  1292. X    trace(("return %ld;\n", (long)srl.wl_nwords));
  1293. X    trace((/*{*/"}\n"));
  1294. X    return srl.wl_nwords;
  1295. X}
  1296. X
  1297. X
  1298. X/*
  1299. X * NAME
  1300. X *    sniff_prepare
  1301. X *
  1302. X * SYNOPSIS
  1303. X *    void sniff_prepare(void);
  1304. X *
  1305. X * DESCRIPTION
  1306. X *    The sniff_prepare function is used to append the standard
  1307. X *    search paths after the user-supplied search paths.
  1308. X */
  1309. X
  1310. Xvoid
  1311. Xsniff_prepare()
  1312. X{
  1313. X    trace(("sniff_prepare()\n{\n"/*}*/));
  1314. X    assert(lang);
  1315. X    lang->prepare();
  1316. X    trace((/*{*/"}\n"));
  1317. X}
  1318. X
  1319. X
  1320. X/*
  1321. X * NAME
  1322. X *    flatten - remove kinks from paths
  1323. X *
  1324. X * SYNOPSIS
  1325. X *    void flatten(char *);
  1326. X *
  1327. X * DESCRIPTION
  1328. X *    The flatten function is used to remove kinks
  1329. X *    from unix path named.
  1330. X *
  1331. X * ARGUMENTS
  1332. X *    path    - path to flatten
  1333. X *
  1334. X * CAVEATS
  1335. X *    It doesn't understand symbolic links.
  1336. X */
  1337. X
  1338. Xstatic string_ty *flatten _((string_ty *));
  1339. X
  1340. Xstatic string_ty *
  1341. Xflatten(s)
  1342. X    string_ty    *s;
  1343. X{
  1344. X    static size_t    tmplen;
  1345. X    static char    *tmp;
  1346. X    char        *in;
  1347. X    char        *out;
  1348. X
  1349. X    /*
  1350. X     * make sure tmp area is big enough
  1351. X     */
  1352. X    trace(("flatten(s = \"%s\")\n{\n"/*}*/, s));
  1353. X    if (s->str_length > tmplen)
  1354. X    {
  1355. X        if (!tmplen)
  1356. X        {
  1357. X            tmplen = s->str_length;
  1358. X            tmp = mem_alloc(tmplen + 1);
  1359. X        }
  1360. X        else
  1361. X        {
  1362. X            tmplen = s->str_length;
  1363. X            mem_change_size(&tmp, tmplen + 1);
  1364. X        }
  1365. X    }
  1366. X
  1367. X    /*
  1368. X     * remove multiple '/'s
  1369. X     */
  1370. X    out = tmp;
  1371. X    for (in = s->str_text; *in; ++in)
  1372. X    {
  1373. X        if (in[0] != '/' || in[1] != '/')
  1374. X            *out++ = *in;
  1375. X    }
  1376. X    *out = 0;
  1377. X
  1378. X    /*
  1379. X     * remove . references
  1380. X     */
  1381. X    in = out = tmp;
  1382. X    if (*in == '/')
  1383. X        *out++ = *in++;
  1384. X    while (*in)
  1385. X    {
  1386. X        if (in[0] == '.' && !in[1])
  1387. X            break;
  1388. X        if (in[0] == '.' && in[1] == '/')
  1389. X        {
  1390. X            in += 2;
  1391. X            continue;
  1392. X        }
  1393. X        while (*in && (*out++ = *in++) != '/')
  1394. X            ;
  1395. X    }
  1396. X    *out = 0;
  1397. X
  1398. X    /*
  1399. X     * remove .. references
  1400. X     */
  1401. X    in = out = tmp;
  1402. X    if (*in == '/')
  1403. X        *out++ = *in++;
  1404. X    while (*in)
  1405. X    {
  1406. X        if (in[0] == '.' && in[1] == '.' && !in[2])
  1407. X        {
  1408. X            if (out == tmp)
  1409. X            {
  1410. X                /* ".." -> ".." */
  1411. X                *out++ = *in++;
  1412. X                *out++ = *in++;
  1413. X                break;
  1414. X            }
  1415. X            if (out == tmp + 1)
  1416. X            {
  1417. X                /* "/.." -> "/" */
  1418. X                break;
  1419. X            }
  1420. X            --out;
  1421. X            while (out > tmp && out[-1] != '/')
  1422. X                --out;
  1423. X            break;
  1424. X        }
  1425. X        if (in[0] == '.' && in[1] == '.' && in[2] == '/')
  1426. X        {
  1427. X            if (out == tmp)
  1428. X            {
  1429. X                /* "../" -> "../" */
  1430. X                *out++ = *in++;
  1431. X                *out++ = *in++;
  1432. X                *out++ = *in++;
  1433. X                continue;
  1434. X            }
  1435. X            if (out == tmp + 1)
  1436. X            {
  1437. X                /* "/../" -> "/" */
  1438. X                in += 3;
  1439. X                continue;
  1440. X            }
  1441. X            --out;
  1442. X            while (out > tmp && out[-1] != '/')
  1443. X                --out;
  1444. X            continue;
  1445. X        }
  1446. X        while (*in && (*out++ = *in++) != '/')
  1447. X            ;
  1448. X    }
  1449. X    *out = 0;
  1450. X
  1451. X    /*
  1452. X     * remove trailing '/'
  1453. X     */
  1454. X    if (out > tmp + 1 && out[-1] == '/')
  1455. X        *--out = 0;
  1456. X
  1457. X    /*
  1458. X     * "" -> "."
  1459. X     */
  1460. X    if (!*tmp)
  1461. X    {
  1462. X        tmp[0] = '.';
  1463. X        tmp[1] = 0;
  1464. X    }
  1465. X
  1466. X    /*
  1467. X     * return a string
  1468. X     */
  1469. X    trace(("return \"%s\";\n", tmp));
  1470. X    trace((/*{*/"}\n"));
  1471. X    return str_from_c(tmp);
  1472. X}
  1473. X
  1474. X
  1475. X/*
  1476. X * NAME
  1477. X *    resolve
  1478. X *
  1479. X * SYNOPSIS
  1480. X *    string_ty *resolve(string_ty *filename, string_ty *extra);
  1481. X *
  1482. X * DESCRIPTION
  1483. X *    The resolve function is used to resolve an include
  1484. X *    filename into the path of an existing file.
  1485. X *
  1486. X * ARGUMENTS
  1487. X *    filename - name to be resolved
  1488. X *    extra    - extra first search element, if not NULL
  1489. X *
  1490. X * RETURNS
  1491. X *    string_ty *; name of path, or NULL if unmentionable
  1492. X */
  1493. X
  1494. Xstatic string_ty *resolve _((string_ty *filename, string_ty *extra));
  1495. X
  1496. Xstatic string_ty *
  1497. Xresolve(filename, extra)
  1498. X    string_ty    *filename;
  1499. X    string_ty    *extra;
  1500. X{
  1501. X    string_ty    *s;
  1502. X    size_t        j;
  1503. X    string_ty    *result;
  1504. X
  1505. X    /*
  1506. X     * If the name is absolute, irrespecitive of
  1507. X     * which style, we need look no further.
  1508. X     */
  1509. X    trace(("resolve(filename = \"%s\", extra = \"%s\")\n{\n"/*}*/,
  1510. X        filename->str_text, extra ? extra->str_text : "NULL"));
  1511. X    if (filename->str_text[0] == '/')
  1512. X    {
  1513. X        result = flatten(filename);
  1514. X        if (os_exists(result->str_text))
  1515. X            goto done;
  1516. X        goto dilema;
  1517. X    }
  1518. X
  1519. X    /*
  1520. X     * Includes of the form "filename" look in the directory
  1521. X     * of the parent file, an then the <filename> places.
  1522. X     */
  1523. X    if (extra)
  1524. X    {
  1525. X        s = str_format("%S/%S", extra, filename);
  1526. X        result = flatten(s);
  1527. X        str_free(s);
  1528. X        if (option.o_verbose)
  1529. X            error("may need to look at \"%s\"", result->str_text);
  1530. X        if (os_exists(result->str_text))
  1531. X            goto done;
  1532. X        str_free(result);
  1533. X    }
  1534. X
  1535. X    /*
  1536. X     * look in all the standard places
  1537. X     */
  1538. X    for (j = 0; j < srl.wl_nwords; ++j)
  1539. X    {
  1540. X        s = str_format("%S/%S", srl.wl_word[j], filename);
  1541. X        result = flatten(s);
  1542. X        str_free(s);
  1543. X        if (option.o_verbose)
  1544. X            error("may need to look at \"%s\"", result->str_text);
  1545. X        if (os_exists(result->str_text))
  1546. X            goto done;
  1547. X        str_free(result);
  1548. X    }
  1549. X
  1550. X    /*
  1551. X     * not found, must have been ifdef'ed out
  1552. X     * or needs to be built
  1553. X     */
  1554. X    dilema:
  1555. X    switch (extra ? option.o_absent_local : option.o_absent_system)
  1556. X    {
  1557. X    default:
  1558. X        fatal("include file \"%s\" not found", filename->str_text);
  1559. X
  1560. X    case absent_ignore:
  1561. X        result = 0;
  1562. X        break;
  1563. X
  1564. X    case absent_mention:
  1565. X        if (extra)
  1566. X        {
  1567. X            s = str_format("%S/%S", extra, filename);
  1568. X            result = flatten(s);
  1569. X            str_free(s);
  1570. X        }
  1571. X        else
  1572. X            result = flatten(filename);
  1573. X        break;
  1574. X    }
  1575. X
  1576. X    /*
  1577. X     * here for all exits
  1578. X     */
  1579. X    done:
  1580. X    trace(("return \"%s\";\n", result ? result->str_text : "NULL"));
  1581. X    trace((/*{*/"}\n"));
  1582. X    return result;
  1583. X}
  1584. X
  1585. X
  1586. X/*
  1587. X * NAME
  1588. X *    stat_equal - compare stat structures
  1589. X *
  1590. X * SYNOPSIS
  1591. X *    vint stat_equal(struct stat *, struct stat *);
  1592. X *
  1593. X * DESCRIPTION
  1594. X *    The stat_equal function is sued to compare two stat structures
  1595. X *    for equality.  Only this fields which would change if
  1596. X *    the file changed are examined.
  1597. X */
  1598. X
  1599. Xstatic int stat_equal _((struct stat *, struct stat *));
  1600. X
  1601. Xstatic int
  1602. Xstat_equal(st1, st2)
  1603. X    struct stat    *st1;
  1604. X    struct stat    *st2;
  1605. X{
  1606. X    return
  1607. X    (
  1608. X        st1->st_dev == st2->st_dev
  1609. X    &&
  1610. X        st1->st_ino == st2->st_ino
  1611. X    &&
  1612. X        st1->st_size == st2->st_size
  1613. X    &&
  1614. X        st1->st_mtime == st2->st_mtime
  1615. X    &&
  1616. X        st1->st_ctime == st2->st_ctime
  1617. X    );
  1618. X}
  1619. X
  1620. X
  1621. X/*
  1622. X * NAME
  1623. X *    sniffer - search file for include dependencies
  1624. X *
  1625. X * SYNOPSIS
  1626. X *    void sniffer(string_ty *pathname);
  1627. X *
  1628. X * DESCRIPTION
  1629. X *    The sniffer function is used to walk a file looking
  1630. X *    for any files which it includes, and walking then also.
  1631. X *    The names of any include files encountered are printed onto
  1632. X *    the standard output.
  1633. X *
  1634. X * ARGUMENTS
  1635. X *    pathname    - pathname to read
  1636. X *    
  1637. X * CAVEATS
  1638. X *    Uses the cache where possible to speed things up.
  1639. X */
  1640. X
  1641. Xstatic void sniffer _((string_ty *));
  1642. X
  1643. Xstatic void
  1644. Xsniffer(filename)
  1645. X    string_ty    *filename;
  1646. X{
  1647. X    FILE        *fp;
  1648. X    cache_ty    *cp;
  1649. X    struct stat    st;
  1650. X    size_t        j;
  1651. X
  1652. X    /*
  1653. X     * find the file in the cache
  1654. X     * (will be created if not already there)
  1655. X     */
  1656. X    trace(("sniffer(filename = \"%s\")\n{\n"/*}*/, filename->str_text));
  1657. X    cp = cache_search(filename);
  1658. X    assert(cp);
  1659. X    if (stat(filename->str_text, &st) < 0)
  1660. X    {
  1661. X        /*
  1662. X         * here for failure to open/find a file
  1663. X         */
  1664. X        absent:
  1665. X        switch (errno)
  1666. X        {
  1667. X        case ENOENT:
  1668. X            break;
  1669. X
  1670. X        case ENOTDIR:
  1671. X        case EACCES:
  1672. X            nerror("%s (warning)", filename->str_text);
  1673. X            break;
  1674. X
  1675. X        default:
  1676. X            nfatal("%s", filename->str_text);
  1677. X        }
  1678. X
  1679. X        /*
  1680. X         * zap the stat info,
  1681. X         * and pretend the file was empty
  1682. X         */
  1683. X        memset(&cp->st, 0, sizeof(cp->st));
  1684. X        wl_free(&cp->ingredients);
  1685. X        cache_update_notify();
  1686. X        if (option.o_verbose)
  1687. X            error("bogus empty \"%s\" file", filename->str_text);
  1688. X        goto done;
  1689. X    }
  1690. X
  1691. X    /*
  1692. X     * if the stat in the cache is not the same
  1693. X     * as the state just obtained, reread the file.
  1694. X     */
  1695. X    if (!stat_equal(&st, &cp->st))
  1696. X    {
  1697. X        wlist    type1;
  1698. X        wlist    type2;
  1699. X
  1700. X        cp->st = st;
  1701. X        wl_free(&cp->ingredients);
  1702. X        cache_update_notify();
  1703. X        if (option.o_verbose)
  1704. X            error("cache miss for \"%s\" file", filename->str_text);
  1705. X
  1706. X        fp = fopen(filename->str_text, "r");
  1707. X        if (!fp)
  1708. X        {
  1709. X            /*
  1710. X             * probably "permission denied" error,
  1711. X             * but file could have suddenly vanished
  1712. X             */
  1713. X            goto absent;
  1714. X        }
  1715. X        wl_zero(&type1);
  1716. X        wl_zero(&type2);
  1717. X        if (lang->scan(fp, &type1, &type2) || fclose(fp))
  1718. X            nfatal("%s", filename->str_text);
  1719. X
  1720. X        /*
  1721. X         * type2 names have an implicit first element of the search path
  1722. X         * which is the directory of the including file
  1723. X         */
  1724. X        if (type2.wl_nwords)
  1725. X        {
  1726. X            string_ty    *parent;
  1727. X            char        *ep;
  1728. X            char        *sp;
  1729. X
  1730. X            sp = filename->str_text;
  1731. X            ep = strrchr(sp, '/');
  1732. X            if (ep)
  1733. X                parent = str_n_from_c(sp, ep - sp);
  1734. X            else
  1735. X                parent = str_from_c(".");
  1736. X            for (j = 0; j < type2.wl_nwords; ++j)
  1737. X            {
  1738. X                string_ty    *path;
  1739. X
  1740. X                path = resolve(type2.wl_word[j], parent);
  1741. X                if (path)
  1742. X                {
  1743. X                    wl_append_unique(&cp->ingredients, path);
  1744. X                    str_free(path);
  1745. X                }
  1746. X            }
  1747. X            str_free(parent);
  1748. X        }
  1749. X
  1750. X        /*
  1751. X         * type1 names scan the search path
  1752. X         */
  1753. X        for (j = 0; j < type1.wl_nwords; ++j)
  1754. X        {
  1755. X            string_ty    *path;
  1756. X
  1757. X            path = resolve(type1.wl_word[j], (string_ty *)0);
  1758. X            if (path)
  1759. X            {
  1760. X                wl_append_unique(&cp->ingredients, path);
  1761. X                str_free(path);
  1762. X            }
  1763. X        }
  1764. X
  1765. X        /*
  1766. X         * let the lists go
  1767. X         */
  1768. X        wl_free(&type1);
  1769. X        wl_free(&type2);
  1770. X    }
  1771. X
  1772. X    /*
  1773. X     * work down the ingredients list
  1774. X     * to see if there are more dependencies
  1775. X     */
  1776. X    wl_append_unique(&visited, filename);
  1777. X    for (j = 0; j < cp->ingredients.wl_nwords; ++j)
  1778. X    {
  1779. X        string_ty    *s;
  1780. X
  1781. X        s = cp->ingredients.wl_word[j];
  1782. X        if (!wl_member(&visited, s))
  1783. X        {
  1784. X            printf("%s\n", s->str_text);
  1785. X            sniffer(s);
  1786. X        }
  1787. X    }
  1788. X
  1789. X    /*
  1790. X     * here for all exits
  1791. X     */
  1792. X    done:
  1793. X    trace((/*{*/"}\n"));
  1794. X}
  1795. X
  1796. X
  1797. X/*
  1798. X * NAME
  1799. X *    sniff - search file for include dependencies
  1800. X *
  1801. X * SYNOPSIS
  1802. X *    void sniff(char *pathname);
  1803. X *
  1804. X * DESCRIPTION
  1805. X *    The sniff function is used to walk a file looking
  1806. X *    for any files which it includes, and walking then also.
  1807. X *    The names of any include files encountered are printed onto
  1808. X *    the standard output.
  1809. X *
  1810. X * ARGUMENTS
  1811. X *    pathname    - pathname to read
  1812. X */
  1813. X
  1814. Xvoid
  1815. Xsniff(filename)
  1816. X    char        *filename;
  1817. X{
  1818. X    string_ty    *s;
  1819. X
  1820. X    assert(filename);
  1821. X    trace(("sniff(filename = \"%s\")\n{\n"/*}*/, filename));
  1822. X    if (!os_exists(filename) && option.o_absent_program == absent_error)
  1823. X        fatal("%s: no such file", filename);
  1824. X    s = str_from_c(filename);
  1825. X    sniffer(s);
  1826. X    str_free(s);
  1827. X    trace((/*{*/"}\n"));
  1828. X}
  1829. END_OF_FILE
  1830. if test 11352 -ne `wc -c <'c_incl/sniff.c'`; then
  1831.     echo shar: \"'c_incl/sniff.c'\" unpacked with wrong size!
  1832. fi
  1833. # end of 'c_incl/sniff.c'
  1834. fi
  1835. if test -f 'common/arglex.c' -a "${1}" != "-c" ; then 
  1836.   echo shar: Will not clobber existing file \"'common/arglex.c'\"
  1837. else
  1838. echo shar: Extracting \"'common/arglex.c'\" \(11998 characters\)
  1839. sed "s/^X//" >'common/arglex.c' <<'END_OF_FILE'
  1840. X/*
  1841. X *    cook - file construction tool
  1842. X *    Copyright (C) 1990, 1991, 1992, 1993 Peter Miller.
  1843. X *    All rights reserved.
  1844. X *
  1845. X *    This program is free software; you can redistribute it and/or modify
  1846. X *    it under the terms of the GNU General Public License as published by
  1847. X *    the Free Software Foundation; either version 2 of the License, or
  1848. X *    (at your option) any later version.
  1849. X *
  1850. X *    This program is distributed in the hope that it will be useful,
  1851. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  1852. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1853. X *    GNU General Public License for more details.
  1854. X *
  1855. X *    You should have received a copy of the GNU General Public License
  1856. X *    along with this program; if not, write to the Free Software
  1857. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1858. X *
  1859. X * MANIFEST: functions to perform lexical analysis on command line arguments
  1860. X */
  1861. X
  1862. X#include <stddef.h>
  1863. X#include <stdlib.h>
  1864. X#include <string.h>
  1865. X#include <ctype.h>
  1866. X
  1867. X#include <main.h>
  1868. X#include <arglex.h>
  1869. X#include <error.h>
  1870. X#include <word.h>
  1871. X#include <mem.h>
  1872. X#include <trace.h>
  1873. X
  1874. Xstatic arglex_table_ty table[] =
  1875. X{
  1876. X    { "-",            arglex_token_stdio,        },
  1877. X    { "-Help",        arglex_token_help,        },
  1878. X    { "-TRACIng",        arglex_token_tracing,        },
  1879. X    { "-VERSion",        arglex_token_version,        },
  1880. X};
  1881. X
  1882. Xstatic int    argc;
  1883. Xstatic char    **argv;
  1884. Xarglex_value_ty    arglex_value;
  1885. Xarglex_token_ty    arglex_token;
  1886. Xchar        *progname;
  1887. Xstatic arglex_table_ty *utable;
  1888. Xstatic    char    *partial;
  1889. X
  1890. X
  1891. Xstatic char *basename _((char *));
  1892. X
  1893. Xstatic char *
  1894. Xbasename(s)
  1895. X    char    *s;
  1896. X{
  1897. X    char    *bp;
  1898. X    char    *ep;
  1899. X
  1900. X    bp = s;
  1901. X    ep = 0;
  1902. X    while (*s)
  1903. X    {
  1904. X        if (s[0] == '/' && s[1] && s[1] != '/')
  1905. X            bp = s + 1;
  1906. X        if (s > bp && s[0] == '/' && s[-1] != '/')
  1907. X            ep = s;
  1908. X        ++s;
  1909. X    }
  1910. X    if (!ep)
  1911. X        ep = s;
  1912. X    *s = 0;
  1913. X    return bp;
  1914. X}
  1915. X
  1916. X
  1917. X/*
  1918. X * NAME
  1919. X *    arglex_init
  1920. X *
  1921. X * SYNOPSIS
  1922. X *    void arglex_init(int ac, char **av, arglex_table-t *tp);
  1923. X *
  1924. X * DESCRIPTION
  1925. X *    The arglex_init function is used to initialize the
  1926. X *    command line processing.
  1927. X *
  1928. X * ARGUMENTS
  1929. X *    ac    - aergument count, from main
  1930. X *    av    - argument values, from main
  1931. X *    tp    - pointer to table of options
  1932. X *
  1933. X * CAVEAT
  1934. X *    Must be called before the arglex() function.
  1935. X */
  1936. X
  1937. Xvoid
  1938. Xarglex_init(ac, av, tp)
  1939. X    int    ac;
  1940. X    char    **av;
  1941. X    arglex_table_ty *tp;
  1942. X{
  1943. X    progname = basename(av[0]);
  1944. X
  1945. X    argc = ac - 1;
  1946. X    argv = av + 1;
  1947. X    utable = tp;
  1948. X}
  1949. X
  1950. X
  1951. X/*
  1952. X * NAME
  1953. X *    arglex_compare
  1954. X *
  1955. X * SYNOPSIS
  1956. X *    int arglex_compare(char *formal, char *actual);
  1957. X *
  1958. X * DESCRIPTION
  1959. X *    The arglex_compare function is used to compare
  1960. X *    a command line string with a formal spec of the option,
  1961. X *    to see if they compare equal.
  1962. X *
  1963. X *    The actual is case-insensitive.  Uppercase in the formal
  1964. X *    means a mandatory character, while lower case means optional.
  1965. X *    Any number of consecutive optional characters may be supplied
  1966. X *    by actual, but none may be skipped, unless all are skipped to
  1967. X *    the next non-lower-case letter.
  1968. X *
  1969. X *    The underscore (_) is like a lower-case minus,
  1970. X *    it matches "", "-" and "_".
  1971. X *
  1972. X *    The "*" in a pattern matches everything to the end of the line,
  1973. X *    anything after the "*" is ignored.  The rest of the line is pointed
  1974. X *    to by the "partial" variable as a side-effect (else it will be 0).
  1975. X *    This rather ugly feature is to support "-I./dir" type options.
  1976. X *
  1977. X *    A backslash in a pattern nominates an exact match required,
  1978. X *    case must matche excatly here.
  1979. X *    This rather ugly feature is to support "-I./dir" type options.
  1980. X *
  1981. X *    For example: "-project" and "-P' both match "-Project",
  1982. X *    as does "-proJ", but "-prj" does not.
  1983. X *
  1984. X *    For example: "-devDir" and "-d_d' both match "-Development_Directory",
  1985. X *    but "-dvlpmnt_drctry" does not.
  1986. X *
  1987. X *    For example: to match include path specifications, use a pattern
  1988. X *    such as "-\\I*", and the partial global variable will have the
  1989. X *    path in it on return.
  1990. X *
  1991. X * ARGUMENTS
  1992. X *    formal    - the "pattern" for the option
  1993. X *    actual    - what the user supplied
  1994. X *
  1995. X * RETURNS
  1996. X *    int;    zero if no match,
  1997. X *        non-zero if they do match.
  1998. X */
  1999. X
  2000. Xint
  2001. Xarglex_compare(formal, actual)
  2002. X    char    *formal;
  2003. X    char    *actual;
  2004. X{
  2005. X    char    fc;
  2006. X    char    ac;
  2007. X    int    result;
  2008. X
  2009. X    trace(("arglex_compare(formal = \"%s\", actual = \"%s\")\n{\n",
  2010. X        formal, actual));
  2011. X    for (;;)
  2012. X    {
  2013. X        trace_string(formal);
  2014. X        trace_string(actual);
  2015. X        ac = *actual++;
  2016. X        if (isupper(ac))
  2017. X            ac = tolower(ac);
  2018. X        fc = *formal++;
  2019. X        switch (fc)
  2020. X        {
  2021. X        case 0:
  2022. X            result = !ac;
  2023. X            goto done;
  2024. X            
  2025. X        case '_':
  2026. X            if (ac == '-')
  2027. X                break;
  2028. X            /* fall through... */
  2029. X
  2030. X        case 'a': case 'b': case 'c': case 'd': case 'e':
  2031. X        case 'f': case 'g': case 'h': case 'i': case 'j':
  2032. X        case 'k': case 'l': case 'm': case 'n': case 'o':
  2033. X        case 'p': case 'q': case 'r': case 's': case 't':
  2034. X        case 'u': case 'v': case 'w': case 'x': case 'y':
  2035. X        case 'z': 
  2036. X            /*
  2037. X             * optional characters
  2038. X             */
  2039. X            if (ac == fc && arglex_compare(formal, actual))
  2040. X            {
  2041. X                result = 1;
  2042. X                goto done;
  2043. X            }
  2044. X            /*
  2045. X             * skip forward to next
  2046. X             * mandatory character, or after '_'
  2047. X             */
  2048. X            while (islower(*formal))
  2049. X                ++formal;
  2050. X            if (*formal == '_')
  2051. X            {
  2052. X                ++formal;
  2053. X                if (ac == '_' || ac == '-')
  2054. X                    ++actual;
  2055. X            }
  2056. X            --actual;
  2057. X            break;
  2058. X
  2059. X        case '*':
  2060. X            /*
  2061. X             * This is a hack, it should really 
  2062. X             * check for a match match the stuff after
  2063. X             * the '*', too, a la glob.
  2064. X             */
  2065. X            if (!ac)
  2066. X            {
  2067. X                result = 0;
  2068. X                goto done;
  2069. X            }
  2070. X            partial = actual - 1;
  2071. X            result = 1;
  2072. X            goto done;
  2073. X
  2074. X        case '\\':
  2075. X            if (actual[-1] != *formal++)
  2076. X            {
  2077. X                result = 0;
  2078. X                goto done;
  2079. X            }
  2080. X            break;
  2081. X
  2082. X        case 'A': case 'B': case 'C': case 'D': case 'E':
  2083. X        case 'F': case 'G': case 'H': case 'I': case 'J':
  2084. X        case 'K': case 'L': case 'M': case 'N': case 'O':
  2085. X        case 'P': case 'Q': case 'R': case 'S': case 'T':
  2086. X        case 'U': case 'V': case 'W': case 'X': case 'Y':
  2087. X        case 'Z': 
  2088. X            fc = tolower(fc);
  2089. X            /* fall through... */
  2090. X
  2091. X        default:
  2092. X            /*
  2093. X             * mandatory characters
  2094. X             */
  2095. X            if (fc != ac)
  2096. X            {
  2097. X                result = 0;
  2098. X                goto done;
  2099. X            }
  2100. X            break;
  2101. X        }
  2102. X    }
  2103. X    done:
  2104. X    trace(("return %d;\n}\n", result));
  2105. X    return result;
  2106. X}
  2107. X
  2108. X
  2109. X/*
  2110. X * NAME
  2111. X *    is_a_number
  2112. X *
  2113. X * SYNOPSIS
  2114. X *    int is_a_number(char *s);
  2115. X *
  2116. X * DESCRIPTION
  2117. X *    The is_a_number function is used to determine if the
  2118. X *    argument is a number.
  2119. X *
  2120. X *    The value is placed in arglex_value.alv_number as
  2121. X *    a side effect.
  2122. X *
  2123. X *    Negative and positive signs are accepted.
  2124. X *    The C conventions for decimal, octal and hexadecimal are understood.
  2125. X *
  2126. X *    There may be no white space anywhere in the string,
  2127. X *    and the string must end after the last digit.
  2128. X *    Trailing garbage will be interpreted to mean it is not a string.
  2129. X *
  2130. X * ARGUMENTS
  2131. X *    s    - string to be tested and evaluated
  2132. X *
  2133. X * RETURNS
  2134. X *    int;    zero if not a number,
  2135. X *        non-zero if is a number.
  2136. X */
  2137. X
  2138. Xstatic int is_a_number _((char *));
  2139. X
  2140. Xstatic int
  2141. Xis_a_number(s)
  2142. X    char        *s;
  2143. X{
  2144. X    long        n;
  2145. X    int        sign;
  2146. X
  2147. X    n = 0;
  2148. X    switch (*s)
  2149. X    {
  2150. X    case '-':
  2151. X        ++s;
  2152. X        sign = -1;
  2153. X        break;
  2154. X
  2155. X    case '+':
  2156. X        ++s;
  2157. X        sign = 1;
  2158. X        break;
  2159. X
  2160. X    default:
  2161. X        sign = 1;
  2162. X        break;
  2163. X    }
  2164. X    switch (*s)
  2165. X    {
  2166. X    case '0':
  2167. X        if ((s[1] == 'x' || s[1] == 'X') && s[2])
  2168. X        {
  2169. X            s += 2;
  2170. X            for (;;)
  2171. X            {
  2172. X                switch (*s)
  2173. X                {
  2174. X                case '0': case '1': case '2': case '3':
  2175. X                case '4': case '5': case '6': case '7':
  2176. X                case '8': case '9':
  2177. X                    n = n * 16 + *s++ - '0';
  2178. X                    continue;
  2179. X
  2180. X                case 'A': case 'B': case 'C':
  2181. X                case 'D': case 'E': case 'F':
  2182. X                    n = n * 16 + *s++ - 'A' + 10;
  2183. X                    continue;
  2184. X
  2185. X                case 'a': case 'b': case 'c':
  2186. X                case 'd': case 'e': case 'f':
  2187. X                    n = n * 16 + *s++ - 'a' + 10;
  2188. X                    continue;
  2189. X                }
  2190. X                break;
  2191. X            }
  2192. X        }
  2193. X        else
  2194. X        {
  2195. X            for (;;)
  2196. X            {
  2197. X                switch (*s)
  2198. X                {
  2199. X                case '0': case '1': case '2': case '3':
  2200. X                case '4': case '5': case '6': case '7':
  2201. X                    n = n * 8 + *s++ - '0';
  2202. X                    continue;
  2203. X                }
  2204. X                break;
  2205. X            }
  2206. X        }
  2207. X        break;
  2208. X
  2209. X    case '1': case '2': case '3': case '4':
  2210. X    case '5': case '6': case '7': case '8': case '9':
  2211. X        for (;;)
  2212. X        {
  2213. X            switch (*s)
  2214. X            {
  2215. X            case '0': case '1': case '2': case '3':
  2216. X            case '4': case '5': case '6': case '7':
  2217. X            case '8': case '9':
  2218. X                n = n * 10 + *s++ - '0';
  2219. X                continue;
  2220. X            }
  2221. X            break;
  2222. X        }
  2223. X        break;
  2224. X
  2225. X    default:
  2226. X        return 0;
  2227. X    }
  2228. X    if (*s)
  2229. X        return 0;
  2230. X    arglex_value.alv_number = n * sign;
  2231. X    return 1;
  2232. X}
  2233. X
  2234. X
  2235. X/*
  2236. X * NAME
  2237. X *    arglex
  2238. X *
  2239. X * SYNOPSIS
  2240. X *    arglex_token_ty arglex(void);
  2241. X *
  2242. X * DESCRIPTION
  2243. X *    The arglex function is used to perfom lexical analysis
  2244. X *    on the command line arguments.
  2245. X *
  2246. X *    Unrecognised options are returned as arglex_token_option
  2247. X *    for anything starting with a '-', or
  2248. X *    arglex_token_string otherwise.
  2249. X *
  2250. X * RETURNS
  2251. X *    The next token in the token stream.
  2252. X *    When the end is reached, arglex_token_eoln is returned forever.
  2253. X *
  2254. X * CAVEAT
  2255. X *    Must call arglex_init befor this function is called.
  2256. X */
  2257. X
  2258. Xarglex_token_ty
  2259. Xarglex()
  2260. X{
  2261. X    arglex_table_ty    *tp;
  2262. X    int        j;
  2263. X    arglex_table_ty    *hit[20];
  2264. X    int        nhit;
  2265. X    char        *arg;
  2266. X    static char    *pushback[3];
  2267. X    static int    pushback_depth;
  2268. X
  2269. X    trace(("arglex()\n{\n"/*}*/));
  2270. X    if (pushback_depth)
  2271. X    {
  2272. X        /*
  2273. X         * the second half of a "-foo=bar" style argument.
  2274. X         */
  2275. X        arg = pushback[--pushback_depth];
  2276. X    }
  2277. X    else
  2278. X    {
  2279. X        if (argc <= 0)
  2280. X        {
  2281. X            arglex_token = arglex_token_eoln;
  2282. X            arg = "";
  2283. X            goto done;
  2284. X        }
  2285. X        arg = argv[0];
  2286. X        argc--;
  2287. X        argv++;
  2288. X
  2289. X        /*
  2290. X         * See if it looks like a GNU "-foo=bar" option.
  2291. X         * Split it at the '=' to make it something the
  2292. X         * rest of the code understands.
  2293. X         */
  2294. X        if (arg[0] == '-' && arg[1] != '=')
  2295. X        {
  2296. X            char    *eqp;
  2297. X
  2298. X            eqp = strchr(arg, '=');
  2299. X            if (eqp)
  2300. X            {
  2301. X                pushback[pushback_depth++] = eqp + 1;
  2302. X                *eqp = 0;
  2303. X            }
  2304. X        }
  2305. X
  2306. X        /*
  2307. X         * Turn the GNU-style leading "--"
  2308. X         * into "-" if necessary.
  2309. X         */
  2310. X        if
  2311. X        (
  2312. X            arg[0] == '-'
  2313. X        &&
  2314. X            arg[1] == '-'
  2315. X        &&
  2316. X            arg[2]
  2317. X        &&
  2318. X            !is_a_number(arg + 1)
  2319. X        )
  2320. X            ++arg;
  2321. X    }
  2322. X
  2323. X    /*
  2324. X     * see if it is a number
  2325. X     */
  2326. X    if (is_a_number(arg))
  2327. X    {
  2328. X        arglex_token = arglex_token_number;
  2329. X        goto done;
  2330. X    }
  2331. X
  2332. X    /*
  2333. X     * scan the tables to see what it matches
  2334. X     */
  2335. X    nhit = 0;
  2336. X    partial = 0;
  2337. X    for (tp = table; tp < ENDOF(table); tp++)
  2338. X    {
  2339. X        if (arglex_compare(tp->name, arg))
  2340. X            hit[nhit++] = tp;
  2341. X    }
  2342. X    if (utable)
  2343. X    {
  2344. X        for (tp = utable; tp->name; tp++)
  2345. X        {
  2346. X            if (arglex_compare(tp->name, arg))
  2347. X                hit[nhit++] = tp;
  2348. X        }
  2349. X    }
  2350. X
  2351. X    /*
  2352. X     * deal with unknown or ambiguous options
  2353. X     */
  2354. X    switch (nhit)
  2355. X    {
  2356. X    case 0:
  2357. X        /*
  2358. X         * not found in the tables
  2359. X         */
  2360. X        if (*arg == '-')
  2361. X            arglex_token = arglex_token_option;
  2362. X        else
  2363. X            arglex_token = arglex_token_string;
  2364. X        break;
  2365. X
  2366. X    case 1:
  2367. X        if (partial)
  2368. X            pushback[pushback_depth++] = partial;
  2369. X        arg = hit[0]->name;
  2370. X        arglex_token = hit[0]->token;
  2371. X        break;
  2372. X
  2373. X    default:
  2374. X        {
  2375. X            string_ty    *s1;
  2376. X            string_ty    *s2;
  2377. X
  2378. X            s1 = str_from_c(hit[0]->name);
  2379. X            for (j = 1; j < nhit; ++j)
  2380. X            {
  2381. X                s2 = str_format("%S, %s", s1, hit[j]->name);
  2382. X                str_free(s1);
  2383. X                s1 = s2;
  2384. X            }
  2385. X            fatal
  2386. X            (
  2387. X                "option \"%s\" ambiguous (%s)",
  2388. X                arg,
  2389. X                s1->str_text
  2390. X            );
  2391. X        }
  2392. X    }
  2393. X
  2394. X    /*
  2395. X     * here for all exits
  2396. X     */
  2397. X    done:
  2398. X    arglex_value.alv_string = arg;
  2399. X    trace(("return %d; /* \"%s\" */\n", arglex_token, arg));
  2400. X    trace((/*{*/"}\n"));
  2401. X    return arglex_token;
  2402. X}
  2403. X
  2404. X
  2405. X/*
  2406. X *  NAME
  2407. X *      arglex_init_from_env - initialize analyzer
  2408. X *
  2409. X *  SYNOPSIS
  2410. X *      void arglex_init_from_env(arglex_table_ty *);
  2411. X *
  2412. X *  DESCRIPTION
  2413. X *      The arglex_init_from_env function is used to initialize the command
  2414. X *      line lexical analyzer form the COOK environment variable.
  2415. X *
  2416. X *  RETURNS
  2417. X *      void
  2418. X *
  2419. X *  CAVEAT
  2420. X *      Must be called befor the arglex function.
  2421. X */
  2422. X
  2423. Xvoid
  2424. Xarglex_init_from_env(av0, table)
  2425. X    char    *av0;
  2426. X    arglex_table_ty *table;
  2427. X{
  2428. X    char    *cp1;
  2429. X    char    *cp2;
  2430. X    size_t    ac;
  2431. X    char    **av;
  2432. X
  2433. X    trace(("arglex_init_from_env()\n{\n"));
  2434. X    av0 = basename(av0);
  2435. X    cp1 = mem_alloc(strlen(av0) + 1);
  2436. X    strcpy(cp1, av0);
  2437. X    for (cp2 = cp1; *cp2; ++cp2)
  2438. X    {
  2439. X        if (islower(*cp2))
  2440. X            *cp2 = toupper(*cp2);
  2441. X    }
  2442. X
  2443. X    ac = 0;
  2444. X    av = 0;
  2445. X    *(char **)enlarge(&ac, (char **)&av, sizeof(char *)) = av0;
  2446. X
  2447. X    cp2 = getenv(cp1);
  2448. X    free(cp1);
  2449. X    if (!cp2)
  2450. X        goto done;
  2451. X
  2452. X    /* make a copy so we don't damage the environment copy */
  2453. X    cp1 = mem_alloc(strlen(cp2) + 1);
  2454. X    strcpy(cp1, cp2);
  2455. X
  2456. X    for (;;)
  2457. X    {
  2458. X        while (*cp1 == ' ')
  2459. X            ++cp1;
  2460. X        if (!*cp1)
  2461. X            break;
  2462. X        cp2 = cp1;
  2463. X        while (*++cp1 != ' ' && *cp1)
  2464. X            ;
  2465. X        if (*cp1)
  2466. X            *cp1++ = 0;
  2467. X        *(char **)enlarge(&ac, (char **)&av, sizeof(char *)) = cp2;
  2468. X    }
  2469. X    done:
  2470. X    arglex_init(ac, av, table);
  2471. X    trace((/*{*/"}\n"));
  2472. X}
  2473. X
  2474. Xvoid
  2475. Xarglex_set_progname(argv0)
  2476. X    char    *argv0;
  2477. X{
  2478. X    progname = basename(argv0);
  2479. X}
  2480. END_OF_FILE
  2481. if test 11998 -ne `wc -c <'common/arglex.c'`; then
  2482.     echo shar: \"'common/arglex.c'\" unpacked with wrong size!
  2483. fi
  2484. # end of 'common/arglex.c'
  2485. fi
  2486. if test -f 'config' -a "${1}" != "-c" ; then 
  2487.   echo shar: Will not clobber existing file \"'config'\"
  2488. else
  2489. echo shar: Extracting \"'config'\" \(11021 characters\)
  2490. sed "s/^X//" >'config' <<'END_OF_FILE'
  2491. X/*
  2492. X *    cook - file construction tool
  2493. X *    Copyright (C) 1991, 1992, 1993 Peter Miller.
  2494. X *    All rights reserved.
  2495. X *
  2496. X *    This program is free software; you can redistribute it and/or modify
  2497. X *    it under the terms of the GNU General Public License as published by
  2498. X *    the Free Software Foundation; either version 2 of the License, or
  2499. X *    (at your option) any later version.
  2500. X *
  2501. X *    This program is distributed in the hope that it will be useful,
  2502. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  2503. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2504. X *    GNU General Public License for more details.
  2505. X *
  2506. X *    You should have received a copy of the GNU General Public License
  2507. X *    along with this program; if not, write to the Free Software
  2508. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  2509. X *
  2510. X * MANIFEST: instructions to aegis, per-project configuration
  2511. X */
  2512. X
  2513. X/*
  2514. X * how to build the project
  2515. X *    (actually, how to do an integration build)
  2516. X * mandatory
  2517. X */
  2518. Xbuild_command =
  2519. X    "cook -b ${source aux/Howto.cook} project=$project \
  2520. Xchange=$change version=$version -nl";
  2521. X
  2522. X/*
  2523. X * When do -Integrate_Begin, link the baseline to the integration directory,
  2524. X * rather than copying it.. This should be much faster.
  2525. X *
  2526. X * There is a gotcha: all the recipes in Howto.cook must unlink their targets
  2527. X * before re-creating them, otherwise the baseline will be trashed.
  2528. X */
  2529. Xlink_integration_directory = true;
  2530. X
  2531. X/*
  2532. X * create a new history
  2533. X * always executed as the project owner
  2534. X */
  2535. Xhistory_create_command =
  2536. X    "fhist ${b $history} -create -i $input -p ${d $history} -r";
  2537. X
  2538. X/*
  2539. X * get a file from history
  2540. X * may be executed by developers
  2541. X */
  2542. Xhistory_get_command =
  2543. X    "fhist ${b $history} -e '$edit' -o $output -p ${d $history}";
  2544. X
  2545. X/*
  2546. X * add a new change to the history
  2547. X * always executed as the project owner
  2548. X */
  2549. Xhistory_put_command =
  2550. X    "fhist ${b $history} -u -i $input -p ${d $history} -r";
  2551. X
  2552. X/*
  2553. X * query the topmost edit of a history file
  2554. X * Result to be printed on stdout.
  2555. X * may be executed by developers
  2556. X */
  2557. Xhistory_query_command =
  2558. X    "fhist ${b $history} -l 0 -p ${d $history} -q";
  2559. X
  2560. X/*
  2561. X * difference of 2 files
  2562. X */
  2563. Xdiff_command =
  2564. X    "fcomp -w -s $original $input -o $output";
  2565. X
  2566. X/*
  2567. X * difference of 3 files
  2568. X */
  2569. Xdiff3_command =
  2570. X    "fmerge $original $mostRecent $input -o $output";
  2571. X
  2572. X/*
  2573. X * whenever files are added to or removed from the change,
  2574. X * execute the following command.
  2575. X */
  2576. Xchange_file_command = "rm -f .c_inclrc";
  2577. X
  2578. X/*
  2579. X * new file templates
  2580. X */
  2581. Xfile_template =
  2582. X[
  2583. X    {
  2584. X        pattern = [ "*.[cyl]" ];
  2585. X        body ="\
  2586. X/*\n\
  2587. X *    cook - file construction tool\n\
  2588. X *    Copyright (C) ${date %Y} Peter Miller.\n\
  2589. X *    All rights reserved.\n\
  2590. X *\n\
  2591. X *    This program is free software; you can redistribute it and/or modify\n\
  2592. X *    it under the terms of the GNU General Public License as published by\n\
  2593. X *    the Free Software Foundation; either version 2 of the License, or\n\
  2594. X *    (at your option) any later version.\n\
  2595. X *\n\
  2596. X *    This program is distributed in the hope that it will be useful,\n\
  2597. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  2598. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  2599. X *    GNU General Public License for more details.\n\
  2600. X *\n\
  2601. X *    You should have received a copy of the GNU General Public License\n\
  2602. X *    along with this program; if not, write to the Free Software\n\
  2603. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\
  2604. X *\n\
  2605. X * MANIFEST: functions to manipulate ${basename $fn .c}s\n\
  2606. X */\n";
  2607. X    },
  2608. X    {
  2609. X        pattern = [ "*.h" ];
  2610. X        body = "\
  2611. X/*\n\
  2612. X *    cook - file construction tool\n\
  2613. X *    Copyright (C) ${date %Y} Peter Miller.\n\
  2614. X *    All rights reserved.\n\
  2615. X *\n\
  2616. X *    This program is free software; you can redistribute it and/or modify\n\
  2617. X *    it under the terms of the GNU General Public License as published by\n\
  2618. X *    the Free Software Foundation; either version 2 of the License, or\n\
  2619. X *    (at your option) any later version.\n\
  2620. X *\n\
  2621. X *    This program is distributed in the hope that it will be useful,\n\
  2622. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  2623. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  2624. X *    GNU General Public License for more details.\n\
  2625. X *\n\
  2626. X *    You should have received a copy of the GNU General Public License\n\
  2627. X *    along with this program; if not, write to the Free Software\n\
  2628. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\
  2629. X *\n\
  2630. X * MANIFEST: interface definition for ${basename $fn .c}\n\
  2631. X */\n\
  2632. X\n\
  2633. X#ifndef ${upcase ${id $fn}}\n\
  2634. X#define ${upcase ${id $fn}}\n\
  2635. X\n\
  2636. X#include <main.h>\n\
  2637. X\n\
  2638. X#endif /* ${upcase ${id $fn}} */\n";
  2639. X    },
  2640. X    {
  2641. X        pattern = [ "test/*/*.sh" ];
  2642. X        body = "\
  2643. X#! /bin/sh\n\
  2644. X#\n\
  2645. X#    cook - file construction tool\n\
  2646. X#    Copyright (C) ${date %Y} Peter Miller.\n\
  2647. X#    All rights reserved.\n\
  2648. X#\n\
  2649. X#    This program is free software; you can redistribute it and/or modify\n\
  2650. X#    it under the terms of the GNU General Public License as published by\n\
  2651. X#    the Free Software Foundation; either version 2 of the License, or\n\
  2652. X#    (at your option) any later version.\n\
  2653. X#\n\
  2654. X#    This program is distributed in the hope that it will be useful,\n\
  2655. X#    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  2656. X#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  2657. X#    GNU General Public License for more details.\n\
  2658. X#\n\
  2659. X#    You should have received a copy of the GNU General Public License\n\
  2660. X#    along with this program; if not, write to the Free Software\n\
  2661. X#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\
  2662. X#\n\
  2663. X# MANIFEST: Test the ??? functionality\n\
  2664. X#\n\
  2665. X\n\
  2666. Xwork=/tmp/$$$$\n\
  2667. XPAGER=cat\n\
  2668. Xexport PAGER\n\
  2669. X\n\
  2670. Xhere=`pwd`\n\
  2671. Xif test $$? -ne 0 ; then exit 1; fi\n\
  2672. X\n\
  2673. Xfail()\n\
  2674. X{\n\
  2675. X    set +x\n\
  2676. X    echo 'FAILED test of the ??? functionality' 1>&2\n\
  2677. X    cd $$here\n\
  2678. X    find $$work -type d -user $$USER -exec chmod u+w {} \\;\n\
  2679. X    rm -rf $$work\n\
  2680. X    exit 1\n\
  2681. X}\n\
  2682. Xpass()\n\
  2683. X{\n\
  2684. X    set +x\n\
  2685. X    echo PASSED 1>&2\n\
  2686. X    cd $$here\n\
  2687. X    find $$work -type d -user $$USER -exec chmod u+w {} \\;\n\
  2688. X    rm -rf $$work\n\
  2689. X    exit 0\n\
  2690. X}\n\
  2691. Xtrap \"fail\" 1 2 3 15\n\
  2692. X\n\
  2693. Xmkdir $$work\n\
  2694. Xif test $$? -ne 0 ; then exit 1; fi\n\
  2695. Xcd $$work\n\
  2696. Xif test $$? -ne 0 ; then fail; fi\n\
  2697. X\n\
  2698. X#\n\
  2699. X# put your test here\n\
  2700. X#\n\
  2701. X$$here/myprog\n\
  2702. Xif test $$? -ne 0 ; then fail; fi\n\
  2703. X\n\
  2704. X#\n\
  2705. X# Only definite negatives are possible.\n\
  2706. X# The functionality exercised by this test appears to work,\n\
  2707. X# no other guarantees are made.\n\
  2708. X#\n\
  2709. Xpass\n";
  2710. X    },
  2711. X    {
  2712. X        pattern = [ "*.sh" ];
  2713. X        body = "\
  2714. X#! /bin/sh\n\
  2715. X#\n\
  2716. X#    cook - file construction tool\n\
  2717. X#    Copyright (C) ${date %Y} Peter Miller.\n\
  2718. X#    All rights reserved.\n\
  2719. X#\n\
  2720. X#    This program is free software; you can redistribute it and/or modify\n\
  2721. X#    it under the terms of the GNU General Public License as published by\n\
  2722. X#    the Free Software Foundation; either version 2 of the License, or\n\
  2723. X#    (at your option) any later version.\n\
  2724. X#\n\
  2725. X#    This program is distributed in the hope that it will be useful,\n\
  2726. X#    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  2727. X#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  2728. X#    GNU General Public License for more details.\n\
  2729. X#\n\
  2730. X#    You should have received a copy of the GNU General Public License\n\
  2731. X#    along with this program; if not, write to the Free Software\n\
  2732. X#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\
  2733. X#\n\
  2734. X# MANIFEST: shell script to ${basename $fn .sh}\n\
  2735. X#\n\
  2736. X\n\
  2737. Xexit 0\n";
  2738. X    },
  2739. X    {
  2740. X        pattern = [ "*.man", "*.[12345678]" ];
  2741. X        body = "\
  2742. X'\\\" t\n\
  2743. X.\\\"    cook - file construction tool\n\
  2744. X.\\\"    Copyright (C) ${date %Y} Peter Miller.\n\
  2745. X.\\\"    All rights reserved.\n\
  2746. X.\\\"\n\
  2747. X.\\\"    This program is free software; you can redistribute it and/or modify\n\
  2748. X.\\\"    it under the terms of the GNU General Public License as published by\n\
  2749. X.\\\"    the Free Software Foundation; either version 2 of the License, or\n\
  2750. X.\\\"    (at your option) any later version.\n\
  2751. X.\\\"\n\
  2752. X.\\\"    This program is distributed in the hope that it will be useful,\n\
  2753. X.\\\"    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  2754. X.\\\"    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  2755. X.\\\"    GNU General Public License for more details.\n\
  2756. X.\\\"\n\
  2757. X.\\\"    You should have received a copy of the GNU General Public License\n\
  2758. X.\\\"    along with this program; if not, write to the Free Software\n\
  2759. X.\\\"    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\
  2760. X.\\\"\n\
  2761. X.\\\" MANIFEST: manual entry for the ${basename $fn .1} command\n\
  2762. X.\\\"\n\
  2763. X.TH cook 1\n\
  2764. X.ds n) cook\n\
  2765. X.if n .ad l\n\
  2766. X.if n .hy 0\n\
  2767. X.if n .nr IN 8n\n\
  2768. X.SH NAME\n\
  2769. X\\*(n) \\- file construction tool\n\
  2770. X.SH SYNOPSIS\n\
  2771. X.B \\*(n)\n\
  2772. X[\n\
  2773. X.IR option \\&...\n\
  2774. X]\n\
  2775. X.IR filename \\&...\n\
  2776. X.br\n\
  2777. X.B \\*(n)\n\
  2778. X.B -Help\n\
  2779. X.br\n\
  2780. X.B \\*(n)\n\
  2781. X.B -VERSion\n\
  2782. X.SH DESCRIPTION\n\
  2783. XThe\n\
  2784. X.I \\*(n)\n\
  2785. Xprogram is used to\n\
  2786. X.br\n\
  2787. X.ne 1i\n\
  2788. X.SH OPTIONS\n\
  2789. XThe following options are understood:\n\
  2790. X.TP 8n\n\
  2791. X.B -Help\n\
  2792. X.br\n\
  2793. XProvide some help with using the\n\
  2794. X.I \\*(n)\n\
  2795. Xprogram.\n\
  2796. X.TP 8n\n\
  2797. X.B -VERSion\n\
  2798. X.br\n\
  2799. XPrint the version of the\n\
  2800. X.I \\*(n)\n\
  2801. Xprogram being executed.\n\
  2802. X.PP\n\
  2803. XAll other options will produce a diagnostic error.\n\
  2804. X.so o__rules.so\n\
  2805. X.so copyright.so\n";
  2806. X    },
  2807. X    {
  2808. X        pattern = [ "*.so", "*.ms", "*.me" ];
  2809. X        body = "\
  2810. X.\\\"\n\
  2811. X.\\\"    cook - file construction tool\n\
  2812. X.\\\"    Copyright (C) ${date %Y} Peter Miller.\n\
  2813. X.\\\"    All rights reserved.\n\
  2814. X.\\\"\n\
  2815. X.\\\"    This program is free software; you can redistribute it and/or modify\n\
  2816. X.\\\"    it under the terms of the GNU General Public License as published by\n\
  2817. X.\\\"    the Free Software Foundation; either version 2 of the License, or\n\
  2818. X.\\\"    (at your option) any later version.\n\
  2819. X.\\\"\n\
  2820. X.\\\"    This program is distributed in the hope that it will be useful,\n\
  2821. X.\\\"    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  2822. X.\\\"    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  2823. X.\\\"    GNU General Public License for more details.\n\
  2824. X.\\\"\n\
  2825. X.\\\"    You should have received a copy of the GNU General Public License\n\
  2826. X.\\\"    along with this program; if not, write to the Free Software\n\
  2827. X.\\\"    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\
  2828. X.\\\"\n\
  2829. X.\\\" MANIFEST: document describing ${basename $fn}\n\
  2830. X.\\\"\n";
  2831. X    },
  2832. X    {
  2833. X        pattern = [ "*" ];
  2834. X        body = "\
  2835. X#\n\
  2836. X#    cook - file construction tool\n\
  2837. X#    Copyright (C) ${date %Y} Peter Miller.\n\
  2838. X#    All rights reserved.\n\
  2839. X#\n\
  2840. X#    This program is free software; you can redistribute it and/or modify\n\
  2841. X#    it under the terms of the GNU General Public License as published by\n\
  2842. X#    the Free Software Foundation; either version 2 of the License, or\n\
  2843. X#    (at your option) any later version.\n\
  2844. X#\n\
  2845. X#    This program is distributed in the hope that it will be useful,\n\
  2846. X#    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  2847. X#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  2848. X#    GNU General Public License for more details.\n\
  2849. X#\n\
  2850. X#    You should have received a copy of the GNU General Public License\n\
  2851. X#    along with this program; if not, write to the Free Software\n\
  2852. X#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\
  2853. X#\n\
  2854. X# MANIFEST: fill me in\n\
  2855. X#\n";
  2856. X    }
  2857. X];
  2858. END_OF_FILE
  2859. if test 11021 -ne `wc -c <'config'`; then
  2860.     echo shar: \"'config'\" unpacked with wrong size!
  2861. fi
  2862. # end of 'config'
  2863. fi
  2864. if test -f 'cook/expr.c' -a "${1}" != "-c" ; then 
  2865.   echo shar: Will not clobber existing file \"'cook/expr.c'\"
  2866. else
  2867. echo shar: Extracting \"'cook/expr.c'\" \(12316 characters\)
  2868. sed "s/^X//" >'cook/expr.c' <<'END_OF_FILE'
  2869. X/*
  2870. X *    cook - file construction tool
  2871. X *    Copyright (C) 1990, 1991, 1992, 1993 Peter Miller.
  2872. X *    All rights reserved.
  2873. X *
  2874. X *    This program is free software; you can redistribute it and/or modify
  2875. X *    it under the terms of the GNU General Public License as published by
  2876. X *    the Free Software Foundation; either version 2 of the License, or
  2877. X *    (at your option) any later version.
  2878. X *
  2879. X *    This program is distributed in the hope that it will be useful,
  2880. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  2881. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2882. X *    GNU General Public License for more details.
  2883. X *
  2884. X *    You should have received a copy of the GNU General Public License
  2885. X *    along with this program; if not, write to the Free Software
  2886. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  2887. X *
  2888. X * MANIFEST: functions to manipulate expression trees
  2889. X *
  2890. X * This file contains the functions for manipulating expression
  2891. X * trees; building, interpreting and freeing them.
  2892. X */
  2893. X
  2894. X#include <stddef.h>
  2895. X#include <stdio.h>
  2896. X
  2897. X#include <builtin.h>
  2898. X#include <conf.h>
  2899. X#include <cook.h>
  2900. X#include <error.h>
  2901. X#include <expr.h>
  2902. X#include <id.h>
  2903. X#include <lex.h>
  2904. X#include <match.h>
  2905. X#include <mem.h>
  2906. X#include <option.h>
  2907. X#include <stmt.h>
  2908. X#include <s-v-arg.h>
  2909. X#include <trace.h>
  2910. X#include <word.h>
  2911. X
  2912. X
  2913. Xstatic  position     *expr_context;
  2914. X
  2915. X
  2916. X/*
  2917. X * NAME
  2918. X *    expr_alloc - allocate a pointer structure
  2919. X *
  2920. X * SYNOPSIS
  2921. X *    expr *expr_alloc(void);
  2922. X *
  2923. X * DESCRIPTION
  2924. X *    The expr_alloc function is used to allocate an expression node
  2925. X *    structure in dynamic memory.  It will initially be filled with zeros.
  2926. X *    The e_op field is defined as being non-zero to allow detection
  2927. X *    of some classes of missuse of the expression nodes.
  2928. X *
  2929. X * RETURNS
  2930. X *    A pointer to a "expr" in dynamic memory.
  2931. X *
  2932. X * CAVEAT
  2933. X *    The expression node is allocated in dynamic memory,
  2934. X *    it is the callers responsibility to ensure that it is freed
  2935. X *    when it is finished with, by a call to expr_free().
  2936. X */
  2937. X
  2938. Xexpr *
  2939. Xexpr_alloc()
  2940. X{
  2941. X    expr    *ep;
  2942. X
  2943. X    trace(("expr_alloc()\n{\n"/*}*/));
  2944. X    ep = (expr *)mem_alloc_clear(sizeof(expr));
  2945. X    ep->e_references = 1;
  2946. X    ep->e_position.pos_name = str_copy(lex_cur_file());
  2947. X    ep->e_position.pos_line = lex_cur_line();
  2948. X    trace(("return %08lX;\n", ep));
  2949. X    trace((/*{*/"}\n"));
  2950. X    return ep;
  2951. X}
  2952. X
  2953. X
  2954. X/*
  2955. X * NAME
  2956. X *    expr_copy - copy and expression
  2957. X *
  2958. X * SYNOPSIS
  2959. X *    expr *expr_copy(expr *);
  2960. X *
  2961. X * DESCRIPTION
  2962. X *    The expr_copy function is used to make a copy of an expression tree.
  2963. X *
  2964. X * RETURNS
  2965. X *    The expr_copy function returns a pointer to the root of the copied
  2966. X *    expression tree.
  2967. X *
  2968. X * CAVEAT
  2969. X *    The result is in dynamic memory, used expr_free to dispose of it when
  2970. X *    finished with.
  2971. X */
  2972. X
  2973. Xexpr *
  2974. Xexpr_copy(ep)
  2975. X    expr    *ep;
  2976. X{
  2977. X    trace(("expr_copy(ep = %08X)\n{\n"/*}*/, ep));
  2978. X    ep->e_references++;
  2979. X    trace(("return %08lX;\n", ep));
  2980. X    trace((/*{*/"}\n"));
  2981. X    return ep;
  2982. X}
  2983. X
  2984. X
  2985. X/*
  2986. X * NAME
  2987. X *    expr_free - free expression tree
  2988. X *
  2989. X * SYNOPSIS
  2990. X *    void expr_free(expr *ep);
  2991. X *
  2992. X * DESCRIPTION
  2993. X *    The expr_free function is used to free expression trees.
  2994. X *
  2995. X * CAVEAT
  2996. X *    It is assumed that the expression trees are all
  2997. X *    dynamically allocated.  Use expr_alloc() to allocate them.
  2998. X */
  2999. X
  3000. Xvoid
  3001. Xexpr_free(ep)
  3002. X    expr    *ep;
  3003. X{
  3004. X    trace(("expr_free(ep = %08X)\n{\n"/*}*/, ep));
  3005. X    assert(ep);
  3006. X    ep->e_references--;
  3007. X    if (ep->e_references > 0)
  3008. X        goto ret;
  3009. X    str_free(ep->e_position.pos_name);
  3010. X    switch ((int)ep->e_op)
  3011. X    {
  3012. X    default:
  3013. X        fatal("illegal expression opcode %d (bug)", ep->e_op);
  3014. X
  3015. X    case OP_CAT:
  3016. X        expr_free(ep->e_left);
  3017. X        expr_free(ep->e_right);
  3018. X        break;
  3019. X
  3020. X    case OP_FUNC:
  3021. X        el_free(&ep->e_list);
  3022. X        break;
  3023. X
  3024. X    case OP_WORD:
  3025. X        str_free(ep->e_word);
  3026. X        break;
  3027. X    }
  3028. X    mem_free((char *)ep);
  3029. Xret:
  3030. X    trace((/*{*/"}\n"));
  3031. X}
  3032. X
  3033. X
  3034. X/*
  3035. X * NAME
  3036. X *    el_free - free expression lists
  3037. X *
  3038. X * SYNOPSIS
  3039. X *    void el_free(elist *elp);
  3040. X *
  3041. X * DESCRIPTION
  3042. X *    The el_free function is used to free expression lists,
  3043. X *    it calls expr_free for each expression in the list.
  3044. X *
  3045. X * CAVEAT
  3046. X *    It is assumed that the expressions are dynamically allocated,
  3047. X *    and that the expression list was grown using el_append().
  3048. X *    The actual structure pointed to is NOT assumed to be in dynamic memory
  3049. X *    and should not be passed to free().
  3050. X */
  3051. X
  3052. Xvoid
  3053. Xel_free(elp)
  3054. X    elist    *elp;
  3055. X{
  3056. X    int    j;
  3057. X
  3058. X    trace(("el_free(elp = %08X)\n{\n"/*}*/, elp));
  3059. X    for (j = 0; j < elp->el_nexprs; j++)
  3060. X        expr_free(elp->el_expr[j]);
  3061. X    if (elp->el_nexprs)
  3062. X        mem_free((char *)elp->el_expr);
  3063. X    elp->el_nexprs = 0;
  3064. X    elp->el_expr = 0;
  3065. X    trace((/*{*/"}\n"));
  3066. X}
  3067. X
  3068. X
  3069. X/*
  3070. X * NAME
  3071. X *    el_copy - copy expression list
  3072. X *
  3073. X * SYNOPSIS
  3074. X *    void el_copy(elist *to, elist *from);
  3075. X *
  3076. X * DESCRIPTION
  3077. X *    The el_copy function is used to copy the list of expression trees
  3078. X *    pointed to by `from' into the expression list pointed to by `to'.
  3079. X *
  3080. X * RETURNS
  3081. X *    void
  3082. X *
  3083. X * CAVEAT
  3084. X *    The el_free function must be used to dispose of the list when
  3085. X *    finished with.
  3086. X */
  3087. X
  3088. Xvoid
  3089. Xel_copy(to, from)
  3090. X    elist    *to;
  3091. X    elist    *from;
  3092. X{
  3093. X    int    j;
  3094. X
  3095. X    trace(("el_copy(to = %08X, from = %08X)\n{\n"/*}*/, to, from));
  3096. X    el_zero(to);
  3097. X    if (!from->el_nexprs)
  3098. X        return;
  3099. X    for (j = 0; j < from->el_nexprs; j++)
  3100. X        el_append(to, from->el_expr[j]);
  3101. X    trace((/*{*/"}\n"));
  3102. X}
  3103. X
  3104. X
  3105. X/*
  3106. X * NAME
  3107. X *    expr_eval - evaluate an expression
  3108. X *
  3109. X * SYNOPSIS
  3110. X *    int expr_eval(wlist *result, expr *ep);
  3111. X *
  3112. X * DESCRIPTION
  3113. X *    The expr_eval function is used to evaluate an expression.
  3114. X *
  3115. X * RETURNS
  3116. X *    The results of the expression evaluation are appended to
  3117. X *    the word list pointed to by 'results' argument using wl_append.
  3118. X *
  3119. X *    The functiuon result is -1 for evaluation errors, 0 for no error.
  3120. X *
  3121. X * CAVEAT
  3122. X *    It is assumed that the results wordlist has been initialised
  3123. X *    before it was passed to expr_eval().
  3124. X *
  3125. X *    The result returned from this function are allocated in dynamic memory.
  3126. X *    It is the responsibility of the caller to ensure that they are freed
  3127. X *    when they are finished with, using wl_free().
  3128. X */
  3129. X
  3130. Xint
  3131. Xexpr_eval(result, ep)
  3132. X    wlist    *result;
  3133. X    expr    *ep;
  3134. X{
  3135. X    int    retval;
  3136. X
  3137. X    trace(("expr_eval(result = %08X, ep = %08X)\n{\n"/*}*/, result, ep));
  3138. X    assert(ep);
  3139. X    switch ((int)ep->e_op)
  3140. X    {
  3141. X    default:
  3142. X        error
  3143. X        (
  3144. X            "%s: %d: illegal expression opcode %d (bug)",
  3145. X            ep->e_position.pos_name->str_text,
  3146. X            ep->e_position.pos_line,
  3147. X            ep->e_op
  3148. X        );
  3149. X        expr_eval_fails:
  3150. X        option_set_errors();
  3151. X        retval = -1;
  3152. X        goto ret;
  3153. X
  3154. X    case OP_WORD:
  3155. X        {
  3156. X            match_ty *field;
  3157. X
  3158. X            /*
  3159. X             * If a wildcard mapping is in force (we are performing
  3160. X             * actions bound to an implicit recipe) the word will be
  3161. X             * mapped before it is returned.
  3162. X             */
  3163. X            field = match_top();
  3164. X            if (field)
  3165. X            {
  3166. X                string_ty *s;
  3167. X
  3168. X                s = reconstruct(ep->e_word, field);
  3169. X                wl_append(result, s);
  3170. X                str_free(s);
  3171. X            }
  3172. X            else
  3173. X                wl_append(result, ep->e_word);
  3174. X        }
  3175. X        break;
  3176. X
  3177. X    case OP_FUNC:
  3178. X        {
  3179. X            wlist     wl;
  3180. X
  3181. X            if (el2wl(&wl, &ep->e_list))
  3182. X            {
  3183. X                wl_free(&wl);
  3184. X                goto expr_eval_fails;
  3185. X            }
  3186. X            switch (wl.wl_nwords)
  3187. X            {
  3188. X            case 0:
  3189. X                break;
  3190. X
  3191. X            case 1:
  3192. X                {
  3193. X                    wlist    value;
  3194. X
  3195. X                    if (id_search(wl.wl_word[0], ID_CLASS_VARIABLE, &value))
  3196. X                    {
  3197. X                        int        j;
  3198. X
  3199. X                        for (j = 0; j < value.wl_nwords; j++)
  3200. X                            wl_append(result, value.wl_word[j]);
  3201. X                        wl_free(&value);
  3202. X                        break;
  3203. X                    }
  3204. X
  3205. X                    /*
  3206. X                     * If the variable is not found,
  3207. X                     * fall through into the function case
  3208. X                     */
  3209. X                }
  3210. X
  3211. X            default:
  3212. X                {
  3213. X                    bifp    code;
  3214. X
  3215. X                    if (!id_search(wl.wl_word[0], ID_CLASS_BUILTIN, &code))
  3216. X                    {
  3217. X                        error
  3218. X                        (
  3219. X                            "%s: %d: undefined %s \"%s\"",
  3220. X                            ep->e_position.pos_name->str_text,
  3221. X                            ep->e_position.pos_line,
  3222. X                            wl.wl_nwords >= 2 ? "function" : "variable",
  3223. X                            wl.wl_word[0]->str_text
  3224. X                        );
  3225. X                        goto expr_eval_fails;
  3226. X                    }
  3227. X                    expr_context = &ep->e_position;
  3228. X                    if ((*code)(result, &wl))
  3229. X                        goto expr_eval_fails;
  3230. X                }
  3231. X                break;
  3232. X            }
  3233. X            wl_free(&wl);
  3234. X        }
  3235. X        break;
  3236. X
  3237. X    case OP_CAT:
  3238. X        {
  3239. X            wlist    left;
  3240. X            wlist    right;
  3241. X            int    j;
  3242. X
  3243. X            /*
  3244. X             * Form the two word lists.
  3245. X             * Tack the last word of the left list
  3246. X             * onto the first word of the right list.
  3247. X             *
  3248. X             * There are other conceivable ways to do this,
  3249. X             * but this definition gives the fewest surprises.
  3250. X             */
  3251. X            wl_zero(&left);
  3252. X            if (expr_eval(&left, ep->e_left))
  3253. X            {
  3254. X                wl_free(&left);
  3255. X                goto expr_eval_fails;
  3256. X            }
  3257. X            wl_zero(&right);
  3258. X            if (expr_eval(&right, ep->e_right))
  3259. X            {
  3260. X                wl_free(&left);
  3261. X                wl_free(&right);
  3262. X                goto expr_eval_fails;
  3263. X            }
  3264. X            switch ((left.wl_nwords ? 1 : 0) | (right.wl_nwords ? 2 : 0))
  3265. X            {
  3266. X            case 0:
  3267. X                /* both lists empty */
  3268. X                break;
  3269. X
  3270. X            case 1:
  3271. X                /* right list empty */
  3272. X                for (j = 0; j < left.wl_nwords; j++)
  3273. X                    wl_append(result, left.wl_word[j]);
  3274. X                break;
  3275. X
  3276. X            case 2:
  3277. X                /* left list empty */
  3278. X                for (j = 0; j < right.wl_nwords; j++)
  3279. X                    wl_append(result, right.wl_word[j]);
  3280. X                break;
  3281. X
  3282. X            case 3:
  3283. X                {
  3284. X                    string_ty *s;
  3285. X
  3286. X                    /* at least one word in each list */
  3287. X                    for (j = 0; j < left.wl_nwords - 1; j++)
  3288. X                        wl_append(result, left.wl_word[j]);
  3289. X                    s = str_catenate(left.wl_word[j], right.wl_word[0]);
  3290. X                    wl_append(result, s);
  3291. X                    str_free(s);
  3292. X                    for (j = 1; j < right.wl_nwords; j++)
  3293. X                        wl_append(result, right.wl_word[j]);
  3294. X                }
  3295. X                break;
  3296. X            }
  3297. X            wl_free(&left);
  3298. X            wl_free(&right);
  3299. X        }
  3300. X        break;
  3301. X    }
  3302. X    retval = 0;
  3303. Xret:
  3304. X    trace(("return %d;\n", retval));
  3305. X    trace((/*{*/"}\n"));
  3306. X    return retval;
  3307. X}
  3308. X
  3309. X
  3310. X/*
  3311. X * NAME
  3312. X *    el_append - append to an expression list
  3313. X *
  3314. X * SYNOPSIS
  3315. X *    void el_append(elist *el, expr *e);
  3316. X *
  3317. X * DESCRIPTION
  3318. X *    The el_append function is used to append an expression to an expression
  3319. X *    list.
  3320. X *
  3321. X * RETURNS
  3322. X *    void
  3323. X *
  3324. X * CAVEAT
  3325. X *    The expression has not been copied, so do not hand it
  3326. X *    to expr_free after you append it.
  3327. X *
  3328. X *    It is assumed that the elist has been previously initialised by a
  3329. X *        elist el;
  3330. X *        el_zero(&el);
  3331. X *    statement (or similar) before this function is called.
  3332. X */
  3333. X
  3334. Xvoid
  3335. Xel_append(el, e)
  3336. X    elist    *el;
  3337. X    expr    *e;
  3338. X{
  3339. X    trace(("el_append(el = %08X, e = %08X)\n{\n"/*}*/, el, e));
  3340. X    assert(el);
  3341. X    assert(e);
  3342. X    assert(!el->el_nexprs || !!el->el_expr);
  3343. X    *(expr **)enlarge(&el->el_nexprs, (char**)&el->el_expr, sizeof(expr *)) = expr_copy(e);
  3344. X    trace((/*{*/"}\n"));
  3345. X}
  3346. X
  3347. X
  3348. X/*
  3349. X * NAME
  3350. X *    el2wl - expression list to word list
  3351. X *
  3352. X * SYNOPSIS
  3353. X *    int el2wl(wlist *wl, elist *el);
  3354. X *
  3355. X * DESCRIPTION
  3356. X *    The el2wl function is used to turn an expression list into a word list.
  3357. X *
  3358. X * RETURNS
  3359. X *    The word list is initialised before it is used to
  3360. X *    store the results of evaluating the expressions.
  3361. X *
  3362. X *    The function return value is -1 for errors and 0 for success.
  3363. X *
  3364. X * CAVEAT
  3365. X *    The results returned by this function are allocated in dynamic memory.
  3366. X *    It is the responsibility of the caller to free them when finished with,
  3367. X *    by a call to wl_free().
  3368. X */
  3369. X
  3370. Xint
  3371. Xel2wl(wlp, elp)
  3372. X    wlist    *wlp;
  3373. X    elist    *elp;
  3374. X{
  3375. X    int    j;
  3376. X    int    retval;
  3377. X
  3378. X    trace(("el2wl(wlp = %08X, elp = %08X)\n{\n"/*}*/, wlp, elp));
  3379. X    retval = 0;
  3380. X    wl_zero(wlp);
  3381. X    for (j = 0; j < elp->el_nexprs; j++)
  3382. X    {
  3383. X        if (expr_eval(wlp, elp->el_expr[j]))
  3384. X        {
  3385. X            retval = -1;
  3386. X            break;
  3387. X        }
  3388. X    }
  3389. X    trace(("return %d;\n", retval));
  3390. X    trace((/*{*/"}\n"));
  3391. X    return retval;
  3392. X}
  3393. X
  3394. X
  3395. X/*
  3396. X * NAME
  3397. X *    expr_eveal_condition - evaluate condition
  3398. X *
  3399. X * SYNOPSIS
  3400. X *    int expr_eval_condition(expr *);
  3401. X *
  3402. X * DESCRIPTION
  3403. X *    The expr_eval_condition function is used to evaluate an expression to
  3404. X *    yeild a true/false result.  The expression is evaluated into a word
  3405. X *    list.  A false result is if all of the resulting strings are empty or
  3406. X *    0, true otherwise.
  3407. X *
  3408. X * RETURNS
  3409. X *    The expr_eval_condition function returns 0 if the condition is false,
  3410. X *    and nonzero if it is true.  The value -1 is returned on error.
  3411. X *
  3412. X * CAVEAT
  3413. X *    The str_bool function is used to test the booean value of a string;
  3414. X *    changeing the behaviour of that function will change the behaviour of
  3415. X *    this one.
  3416. X */
  3417. X
  3418. Xint
  3419. Xexpr_eval_condition(ep)
  3420. X    expr    *ep;
  3421. X{
  3422. X    wlist    wl;
  3423. X    int    j;
  3424. X    int    result;
  3425. X
  3426. X    trace(("expr_eval_condition(ep = %08X)\n{\n"/*}*/, ep));
  3427. X    assert(ep);
  3428. X    wl_zero(&wl);
  3429. X    if (expr_eval(&wl, ep))
  3430. X    {
  3431. X        result = -1;
  3432. X        goto ret;
  3433. X    }
  3434. X    for (j = 0; j < wl.wl_nwords; ++j)
  3435. X    {
  3436. X        if (str_bool(wl.wl_word[j]))
  3437. X        {
  3438. X            wl_free(&wl);
  3439. X            result = 1;
  3440. X            goto ret;
  3441. X        }
  3442. X    }
  3443. X    wl_free(&wl);
  3444. X    result = 0;
  3445. Xret:
  3446. X    trace(("return %d;\n", result));
  3447. X    trace((/*{*/"}\n"));
  3448. X    return result;
  3449. X}
  3450. X
  3451. X
  3452. X/*VARARGS1*/
  3453. Xvoid
  3454. Xexpr_error(s sva_last)
  3455. X    char        *s;
  3456. X    sva_last_decl
  3457. X{
  3458. X    va_list        ap;
  3459. X    char        buffer[1 << 11];
  3460. X
  3461. X    sva_init(ap, s);
  3462. X    vsprintf(buffer, s, ap);
  3463. X    va_end(ap);
  3464. X    error
  3465. X    (
  3466. X        "%s: %d: %s",
  3467. X        expr_context->pos_name->str_text,
  3468. X        expr_context->pos_line,
  3469. X        buffer
  3470. X    );
  3471. X}
  3472. X
  3473. X
  3474. Xvoid
  3475. Xel_zero(elp)
  3476. X    elist    *elp;
  3477. X{
  3478. X    elp->el_nexprs = 0;
  3479. X    elp->el_expr = 0;
  3480. X}
  3481. END_OF_FILE
  3482. if test 12316 -ne `wc -c <'cook/expr.c'`; then
  3483.     echo shar: \"'cook/expr.c'\" unpacked with wrong size!
  3484. fi
  3485. # end of 'cook/expr.c'
  3486. fi
  3487. if test -f 'cook/hashline.y' -a "${1}" != "-c" ; then 
  3488.   echo shar: Will not clobber existing file \"'cook/hashline.y'\"
  3489. else
  3490. echo shar: Extracting \"'cook/hashline.y'\" \(12945 characters\)
  3491. sed "s/^X//" >'cook/hashline.y' <<'END_OF_FILE'
  3492. X/*
  3493. X *    cook - file construction tool
  3494. X *    Copyright (C) 1991, 1992, 1993 Peter Miller.
  3495. X *    All rights reserved.
  3496. X *
  3497. X *    This program is free software; you can redistribute it and/or modify
  3498. X *    it under the terms of the GNU General Public License as published by
  3499. X *    the Free Software Foundation; either version 2 of the License, or
  3500. X *    (at your option) any later version.
  3501. X *
  3502. X *    This program is distributed in the hope that it will be useful,
  3503. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  3504. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  3505. X *    GNU General Public License for more details.
  3506. X *
  3507. X *    You should have received a copy of the GNU General Public License
  3508. X *    along with this program; if not, write to the Free Software
  3509. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  3510. X *
  3511. X * MANIFEST: functions to parse #directive lines in cookbooks
  3512. X #
  3513. X * The hashline.y and parse.y parsers share the same lexer.
  3514. X * This means using the classic sed hack for yacc output.
  3515. X * Note that the expression grammars must be as similar as possible
  3516. X * in the two grammars.
  3517. X *
  3518. X * The state table in the condition frames is very simple:
  3519. X *    state 0: before #if
  3520. X *    state 1: after #if (and variants)
  3521. X *    state 2: after #elif
  3522. X *    state 3: after #else
  3523. X *    state 0: after #endif
  3524. X */
  3525. X
  3526. X%{
  3527. X
  3528. X#include <stddef.h>
  3529. X#include <string.h>
  3530. X#include <time.h>
  3531. X#include <stdlib.h>
  3532. X
  3533. X#include <error.h>
  3534. X#include <expr.h>
  3535. X#include <hashline.h>
  3536. X#include <lex.h>
  3537. X#include <mem.h>
  3538. X#include <option.h>
  3539. X#include <os.h>
  3540. X#include <trace.h>
  3541. X#include <word.h>
  3542. X
  3543. X
  3544. Xstatic wlist done_once;
  3545. X
  3546. X
  3547. Xtypedef struct cond cond;
  3548. Xstruct cond
  3549. X{
  3550. X    int    pass;
  3551. X    int    state;
  3552. X    cond    *next;
  3553. X};
  3554. X
  3555. Xstatic    cond    *stack;
  3556. Xstatic    cond    *cond_free_list;
  3557. X
  3558. X#ifdef DEBUG
  3559. X#define YYDEBUG 1
  3560. X#define printf trace_where(__FILE__, __LINE__), lex_trace
  3561. Xextern int yydebug;
  3562. X#endif
  3563. X
  3564. X
  3565. X#define yyerror lex_error
  3566. X
  3567. X
  3568. X/*
  3569. X * NAME
  3570. X *    open_include - open an include file
  3571. X *
  3572. X * SYNOPSIS
  3573. X *    void open_include(string_ty *filename);
  3574. X *
  3575. X * DESCRIPTION
  3576. X *    The open_include function is used to search for a given file name in
  3577. X *    the include path and lex_open it when found.
  3578. X *
  3579. X * RETURNS
  3580. X *    void
  3581. X */
  3582. X
  3583. Xstatic void open_include_once _((string_ty *));
  3584. X
  3585. Xstatic void
  3586. Xopen_include_once(filename)
  3587. X    string_ty    *filename;
  3588. X{
  3589. X    if (!wl_member(&done_once, filename))
  3590. X        lex_open(filename);
  3591. X}
  3592. X
  3593. X
  3594. Xstatic void open_include _((string_ty *, int));
  3595. X
  3596. Xstatic void
  3597. Xopen_include(filename, local)
  3598. X    string_ty    *filename;
  3599. X    int        local;
  3600. X{
  3601. X    int        j;
  3602. X    string_ty    *path;
  3603. X
  3604. X    trace(("open_include(filename = %08lX, local = %d) entry",
  3605. X        filename, local));
  3606. X    trace_string(filename->str_text);
  3607. X    if (filename->str_text[0] != '/')
  3608. X    {
  3609. X        if (local)
  3610. X        {
  3611. X            string_ty    *s;
  3612. X
  3613. X            s = lex_cur_file();
  3614. X            if (strchr(s->str_text, '/'))
  3615. X            {
  3616. X                s = os_dirname(s);
  3617. X                if (!s)
  3618. X                {
  3619. X                    bomb:
  3620. X                    yyerror("unable to construct include file name");
  3621. X                    goto ret;
  3622. X                }
  3623. X                path = str_format("%S/%S", s, filename);
  3624. X                str_free(s);
  3625. X            }
  3626. X            else
  3627. X                path = str_copy(filename);
  3628. X            switch (os_exists(path))
  3629. X            {
  3630. X            case -1:
  3631. X                str_free(path);
  3632. X                goto bomb;
  3633. X
  3634. X            case 1:
  3635. X                open_include_once(path);
  3636. X                str_free(path);
  3637. X                goto ret;
  3638. X            }
  3639. X            str_free(path);
  3640. X        }
  3641. X        for (j = 0; j < option.o_search_path.wl_nwords; ++j)
  3642. X        {
  3643. X            path = str_format("%S/%S", option.o_search_path.wl_word[j], filename);
  3644. X            switch (os_exists(path))
  3645. X            {
  3646. X            case -1:
  3647. X                str_free(path);
  3648. X                goto bomb;
  3649. X
  3650. X            case 1:
  3651. X                open_include_once(path);
  3652. X                str_free(path);
  3653. X                goto ret;
  3654. X            }
  3655. X            str_free(path);
  3656. X        }
  3657. X    }
  3658. X    open_include_once(filename);
  3659. X    ret:
  3660. X    trace((/*{*/"}\n"));
  3661. X}
  3662. X
  3663. X
  3664. X/*
  3665. X * NAME
  3666. X *    hashline - the # control line processor
  3667. X *
  3668. X * SYNOPSIS
  3669. X *    void hashline(void);
  3670. X *
  3671. X * DESCRIPTION
  3672. X *    The hashline function is used to process # control lines.
  3673. X *
  3674. X * RETURNS
  3675. X *    void
  3676. X */
  3677. X
  3678. Xvoid
  3679. Xhashline()
  3680. X{
  3681. X    int yyparse _((void)); /* forward */
  3682. X
  3683. X    trace(("hashline()\n{\n"/*}*/));
  3684. X#if YYDEBUG
  3685. X    yydebug = trace_pretest_;
  3686. X#endif
  3687. X    yyparse();
  3688. X    trace((/*{*/"}\n"));
  3689. X}
  3690. X
  3691. X
  3692. X/*
  3693. X * NAME
  3694. X *    cond_alloc - allocate a condition structure
  3695. X *
  3696. X * SYNOPSIS
  3697. X *    cond *cond_alloc(void);
  3698. X *
  3699. X * DESCRIPTION
  3700. X *    The cond_alloc function is used to allocate a condition structure
  3701. X *    from dynamic memory.
  3702. X *
  3703. X * RETURNS
  3704. X *    cond * - pointer to condition structure.
  3705. X *
  3706. X * CAVEAT
  3707. X *    A free list is maintained to avoid malloc overheads.
  3708. X */
  3709. X
  3710. Xstatic cond *cond_alloc _((void));
  3711. X
  3712. Xstatic cond *
  3713. Xcond_alloc()
  3714. X{
  3715. X    cond        *c;
  3716. X
  3717. X    if (cond_free_list)
  3718. X    {
  3719. X        c = cond_free_list;
  3720. X        cond_free_list = c->next;
  3721. X    }
  3722. X    else
  3723. X        c = (cond *)mem_alloc(sizeof(cond));
  3724. X    return c;
  3725. X}
  3726. X
  3727. X
  3728. X/*
  3729. X * NAME
  3730. X *    cond_free - free condition structure
  3731. X *
  3732. X * SYNOPSIS
  3733. X *    void cond_free(cond*);
  3734. X *
  3735. X * DESCRIPTION
  3736. X *    The cond_free function is used to indicate that a condition structure
  3737. X *    is finished with.
  3738. X *
  3739. X * RETURNS
  3740. X *    void
  3741. X *
  3742. X * CAVEAT
  3743. X *    A free list is maintained to avoid malloc overheads.
  3744. X */
  3745. X
  3746. Xstatic void cond_free _((cond *));
  3747. X
  3748. Xstatic void
  3749. Xcond_free(c)
  3750. X    cond        *c;
  3751. X{
  3752. X    c->next = cond_free_list;
  3753. X    cond_free_list = c;
  3754. X}
  3755. X
  3756. X/*
  3757. X * NAME
  3758. X *    hash_include - process #include directive
  3759. X *
  3760. X * SYNOPSIS
  3761. X *    void hash_include(expr *filename);
  3762. X *
  3763. X * DESCRIPTION
  3764. X *    The hash_include function is used to process #include directives.
  3765. X *
  3766. X * RETURNS
  3767. X *    void
  3768. X */
  3769. X
  3770. Xstatic void hash_include _((expr *));
  3771. X
  3772. Xstatic void
  3773. Xhash_include(ep)
  3774. X    expr        *ep;
  3775. X{
  3776. X    wlist        result;
  3777. X    string_ty    *s;
  3778. X
  3779. X    if (stack && !stack->pass)
  3780. X        return;
  3781. X    wl_zero(&result);
  3782. X    if (expr_eval(&result, ep))
  3783. X    {
  3784. X        wl_free(&result);
  3785. X        hashline_error("include file name evaluation failed");
  3786. X        return;
  3787. X    }
  3788. X    switch (result.wl_nwords)
  3789. X    {
  3790. X    case 0:
  3791. X        yyerror("expression produces no file name to include");
  3792. X        break;
  3793. X
  3794. X    case 1:
  3795. X        s = result.wl_word[0];
  3796. X        if
  3797. X        (
  3798. X            s->str_length > 2
  3799. X        &&
  3800. X            s->str_text[0] == '<'
  3801. X        &&
  3802. X            s->str_text[s->str_length - 1] == '>'
  3803. X        )
  3804. X        {
  3805. X            s = str_n_from_c(s->str_text + 1, s->str_length - 2);
  3806. X            open_include(s, 0);
  3807. X            str_free(s);
  3808. X        }
  3809. X        else
  3810. X        {
  3811. X            if (s->str_length)
  3812. X                open_include(s, 1);
  3813. X            else
  3814. X                yyerror("expression produces null file name to include");
  3815. X        }
  3816. X        break;
  3817. X
  3818. X    default:
  3819. X        yyerror("expression produces more than one file name to include");
  3820. X        break;
  3821. X    }
  3822. X    wl_free(&result);
  3823. X}
  3824. X
  3825. X
  3826. X/*
  3827. X * NAME
  3828. X *    hash_if - process #if directive
  3829. X *
  3830. X * SYNOPSIS
  3831. X *    void hash_if(expr *);
  3832. X *
  3833. X * DESCRIPTION
  3834. X *    The hash_if function is used to process #if directives.
  3835. X *
  3836. X * RETURNS
  3837. X *    void
  3838. X */
  3839. X
  3840. Xstatic void hash_if _((expr *));
  3841. X
  3842. Xstatic void
  3843. Xhash_if(ep)
  3844. X    expr        *ep;
  3845. X{
  3846. X    cond        *c;
  3847. X
  3848. X    trace(("hash_if(ep = %08lX)\n{\n"/*}*/, ep));
  3849. X    c = cond_alloc();
  3850. X    c->next = stack;
  3851. X    if (stack && !stack->pass)
  3852. X    {
  3853. X        c->pass = 0;
  3854. X        c->state = 1;
  3855. X        lex_passing(0);
  3856. X    }
  3857. X    else
  3858. X    {
  3859. X        switch (expr_eval_condition(ep))
  3860. X        {
  3861. X        case -1:
  3862. X            yyerror("condition evaluation failed");
  3863. X            /* fall through... */
  3864. X
  3865. X        case 0:
  3866. X            c->pass = 0;
  3867. X            c->state = 2;
  3868. X            lex_passing(0);
  3869. X            break;
  3870. X
  3871. X        default:
  3872. X            c->pass = 1;
  3873. X            c->state = 1;
  3874. X            lex_passing(1);
  3875. X            break;
  3876. X        }
  3877. X    }
  3878. X    stack = c;
  3879. X    trace((/*{*/"}\n"));
  3880. X}
  3881. X
  3882. X
  3883. X/*
  3884. X * NAME
  3885. X *    hash_ifdef - process #ifdef directive
  3886. X *
  3887. X * SYNOPSIS
  3888. X *    void hash_ifdef(expr*);
  3889. X *
  3890. X * DESCRIPTION
  3891. X *    The hash_ifdef function is used to process #ifdef directives.
  3892. X *
  3893. X * RETURNS
  3894. X *    void
  3895. X */
  3896. X
  3897. Xstatic void hash_ifdef _((expr *));
  3898. X
  3899. Xstatic void
  3900. Xhash_ifdef(ep)
  3901. X    expr        *ep;
  3902. X{
  3903. X    expr        *e1;
  3904. X    expr        *e2;
  3905. X
  3906. X    trace(("hash_ifdef(ep = %08lX)\n{\n"/*}*/, ep));
  3907. X    e1 = expr_alloc();
  3908. X    e1->e_op = OP_WORD;
  3909. X    e1->e_word = str_from_c("defined");
  3910. X    e2 = expr_alloc();
  3911. X    e2->e_op = OP_FUNC;
  3912. X    el_append(&e2->e_list, e1);
  3913. X    el_append(&e2->e_list, ep);
  3914. X    expr_free(e1);
  3915. X    hash_if(e2);
  3916. X    expr_free(e2);
  3917. X    trace((/*{*/"}\n"));
  3918. X}
  3919. X
  3920. X
  3921. X/*
  3922. X * NAME
  3923. X *    hash_ifndef - process #ifndef directives
  3924. X *
  3925. X * SYNOPSIS
  3926. X *    void hash_ifndef(expr *);
  3927. X *
  3928. X * DESCRIPTION
  3929. X *    The hash_ifndef function is used to process #ifndef directives.
  3930. X *
  3931. X * RETURNS
  3932. X *    void
  3933. X */
  3934. X
  3935. Xstatic void hash_ifndef _((expr *));
  3936. X
  3937. Xstatic void
  3938. Xhash_ifndef(ep)
  3939. X    expr        *ep;
  3940. X{
  3941. X    expr        *e1;
  3942. X    expr        *e2;
  3943. X    expr        *e3;
  3944. X
  3945. X    trace(("hash_ifndef(ep = %08lX)\n{\n"/*}*/, ep));
  3946. X    e1 = expr_alloc();
  3947. X    e1->e_op = OP_WORD;
  3948. X    e1->e_word = str_from_c("defined");
  3949. X    e2 = expr_alloc();
  3950. X    e2->e_op = OP_FUNC;
  3951. X    el_append(&e2->e_list, e1);
  3952. X    el_append(&e2->e_list, ep);
  3953. X    expr_free(e1);
  3954. X
  3955. X    e1 = expr_alloc();
  3956. X    e1->e_op = OP_WORD;
  3957. X    e1->e_word = str_from_c("not");
  3958. X    e3 = expr_alloc();
  3959. X    e3->e_op = OP_FUNC;
  3960. X    el_append(&e3->e_list, e1);
  3961. X    el_append(&e3->e_list, e2);
  3962. X    expr_free(e1);
  3963. X    expr_free(e2);
  3964. X
  3965. X    hash_if(e3);
  3966. X    expr_free(e3);
  3967. X    trace((/*{*/"}\n"));
  3968. X}
  3969. X
  3970. X
  3971. X/*
  3972. X * NAME
  3973. X *    hash_elif - process #elif directive
  3974. X *
  3975. X * SYNOPSIS
  3976. X *    void hash_elif(expr*);
  3977. X *
  3978. X * DESCRIPTION
  3979. X *    The hash_elif function is used to provess #elif directives.
  3980. X *
  3981. X * RETURNS
  3982. X *    void
  3983. X */
  3984. X
  3985. Xstatic void hash_elif _((expr *));
  3986. X
  3987. Xstatic void
  3988. Xhash_elif(ep)
  3989. X    expr        *ep;
  3990. X{
  3991. X    trace(("hash_elif(ep = %08lX)\n{\n"/*}*/, ep));
  3992. X    if (!stack)
  3993. X        yyerror("#elif without matching #if");
  3994. X    else
  3995. X    {
  3996. X        switch (stack->state)
  3997. X        {
  3998. X        case 1:
  3999. X            stack->pass = 0;
  4000. X            stack->state = 1;
  4001. X            lex_passing(0);
  4002. X            break;
  4003. X
  4004. X        case 2:
  4005. X            switch (expr_eval_condition(ep))
  4006. X            {
  4007. X            case -1:
  4008. X                yyerror("condition evaluation failed");
  4009. X                /* fall through... */
  4010. X
  4011. X            case 0:
  4012. X                stack->pass = 0;
  4013. X                stack->state = 2;
  4014. X                lex_passing(0);
  4015. X                break;
  4016. X
  4017. X            default:
  4018. X                stack->pass = 1;
  4019. X                stack->state = 1;
  4020. X                lex_passing(1);
  4021. X                break;
  4022. X            }
  4023. X            break;
  4024. X
  4025. X        case 3:
  4026. X            stack->pass = 0;
  4027. X            stack->state = 3;
  4028. X            yyerror("#elif after #else");
  4029. X            lex_passing(0);
  4030. X            break;
  4031. X        }
  4032. X    }
  4033. X    trace((/*{*/"}\n"));
  4034. X}
  4035. X
  4036. X
  4037. X/*
  4038. X * NAME
  4039. X *    hash_else - process #else directive
  4040. X *
  4041. X * SYNOPSIS
  4042. X *    void hash_else(void);
  4043. X *
  4044. X * DESCRIPTION
  4045. X *    The hash_else function is used to process #else directives.
  4046. X *
  4047. X * RETURNS
  4048. X *    void
  4049. X */
  4050. X
  4051. Xstatic void hash_else _((void));
  4052. X
  4053. Xstatic void
  4054. Xhash_else()
  4055. X{
  4056. X    trace(("hash_else()\n{\n"/*}*/));
  4057. X    if (!stack)
  4058. X        yyerror("#else without matching #if");
  4059. X    else
  4060. X    {
  4061. X        switch (stack->state)
  4062. X        {
  4063. X        case 1:
  4064. X            stack->pass = 0;
  4065. X            stack->state = 3;
  4066. X            lex_passing(0);
  4067. X            break;
  4068. X
  4069. X        case 2:
  4070. X            stack->pass = 1;
  4071. X            stack->state = 3;
  4072. X            lex_passing(1);
  4073. X            break;
  4074. X
  4075. X        case 3:
  4076. X            stack->pass = 0;
  4077. X            stack->state = 3;
  4078. X            yyerror("#else after #else");
  4079. X            lex_passing(0);
  4080. X            break;
  4081. X        }
  4082. X    }
  4083. X    trace((/*{*/"}\n"));
  4084. X}
  4085. X
  4086. X
  4087. X/*
  4088. X * NAME
  4089. X *    hash_endif - process #endif directive
  4090. X *
  4091. X * SYNOPSIS
  4092. X *    void hash_endif(void);
  4093. X *
  4094. X * DESCRIPTION
  4095. X *    The hash_endif function is used to process #endif directives.
  4096. X *
  4097. X * RETURNS
  4098. X *    void
  4099. X */
  4100. X
  4101. Xstatic void hash_endif _((void));
  4102. X
  4103. Xstatic void
  4104. Xhash_endif()
  4105. X{
  4106. X    trace(("hash_endif()\n{\n"/*}*/));
  4107. X    if (!stack)
  4108. X        yyerror("#endif without matching #if");
  4109. X    else
  4110. X    {
  4111. X        cond    *c;
  4112. X
  4113. X        c = stack;
  4114. X        stack = c->next;
  4115. X        cond_free(c);
  4116. X        lex_passing(stack ? stack->pass : 1);
  4117. X    }
  4118. X    trace((/*{*/"}\n"));
  4119. X}
  4120. X
  4121. X
  4122. X/*
  4123. X * NAME
  4124. X *    hash_pragma - process #pragma directive
  4125. X *
  4126. X * SYNOPSIS
  4127. X *    void hash_pragma(elist *elp);
  4128. X *
  4129. X * DESCRIPTION
  4130. X *    The hash_pragma function is used to process #pragma directives.
  4131. X *
  4132. X * RETURNS
  4133. X *    void
  4134. X */
  4135. X
  4136. Xstatic void hash_pragma _((elist *));
  4137. X
  4138. Xstatic void
  4139. Xhash_pragma(elp)
  4140. X    elist        *elp;
  4141. X{
  4142. X    static string_ty    *once;
  4143. X
  4144. X    trace(("hash_if(elp = %08lX)\n{\n"/*}*/, elp));
  4145. X    if (stack && !stack->pass)
  4146. X        goto ret;
  4147. X
  4148. X    /*
  4149. X     * see if it was "#pragma once"
  4150. X     */
  4151. X    if (!once)
  4152. X        once = str_from_c("once");
  4153. X    if
  4154. X    (
  4155. X        elp->el_nexprs == 1
  4156. X    &&
  4157. X        elp->el_expr[0]->e_op == OP_WORD
  4158. X    &&
  4159. X        str_equal(elp->el_expr[0]->e_word, once)
  4160. X    )
  4161. X    {
  4162. X        wl_append_unique(&done_once, lex_cur_file());
  4163. X        goto ret;
  4164. X    }
  4165. X
  4166. X    /*
  4167. X     * add more pragma's here
  4168. X     */
  4169. X
  4170. X    ret:
  4171. X    trace((/*{*/"}\n"));
  4172. X}
  4173. X
  4174. X%}
  4175. X
  4176. X/*
  4177. X * this list must be IDENTICAL to the list in parse.y
  4178. X */
  4179. X%token    CATENATE
  4180. X%token    COLON
  4181. X%token    DATA
  4182. X%token    DATAEND
  4183. X%token    ELSE
  4184. X%token    EQUALS
  4185. X%token    FAIL
  4186. X%token    IF
  4187. X%token    LBRACE
  4188. X%token    LBRAK
  4189. X%token    LOOP
  4190. X%token    LOOPSTOP
  4191. X%token    RBRACE
  4192. X%token    RBRAK
  4193. X%token    SEMICOLON
  4194. X%token    SET
  4195. X%token    THEN
  4196. X%token    UNSETENV
  4197. X%token    WORD
  4198. X
  4199. X/*
  4200. X * this list must not appear in parse.y
  4201. X */
  4202. X%token    HASH_ELIF
  4203. X%token    HASH_ELSE
  4204. X%token    HASH_ENDIF
  4205. X%token    HASH_IF
  4206. X%token    HASH_IFDEF
  4207. X%token    HASH_IFNDEF
  4208. X%token    HASH_INCLUDE
  4209. X%token    HASH_PRAGMA
  4210. X
  4211. X%left    CATENATE
  4212. X%right    ELSE
  4213. X
  4214. X%union
  4215. X{
  4216. X    expr        *lv_expr;
  4217. X    elist        lv_elist;
  4218. X    string_ty    *lv_word;
  4219. X}
  4220. X
  4221. X%type    <lv_elist>    elist
  4222. X%type    <lv_word>    WORD
  4223. X%type    <lv_expr>    expr
  4224. X
  4225. X%%
  4226. X
  4227. X/*
  4228. X * note that the grammar accepts a single line.
  4229. X * this means that 0 (end-of-input) must be sent on end-of-line.
  4230. X */
  4231. X
  4232. Xhashline
  4233. X    : HASH_INCLUDE expr
  4234. X        {
  4235. X            hash_include($2);
  4236. X            expr_free($2);
  4237. X        }
  4238. X    | HASH_IF expr
  4239. X        {
  4240. X            hash_if($2);
  4241. X            expr_free($2);
  4242. X        }
  4243. X    | HASH_IFDEF expr
  4244. X        {
  4245. X            hash_ifdef($2);
  4246. X            expr_free($2);
  4247. X        }
  4248. X    | HASH_IFNDEF expr
  4249. X        {
  4250. X            hash_ifndef($2);
  4251. X            expr_free($2);
  4252. X        }
  4253. X    | HASH_ELIF expr 
  4254. X        {
  4255. X            hash_elif($2);
  4256. X            expr_free($2);
  4257. X        }
  4258. X    | HASH_ELSE 
  4259. X        {
  4260. X            hash_else();
  4261. X        }
  4262. X    | HASH_ENDIF 
  4263. X        {
  4264. X            hash_endif();
  4265. X        }
  4266. X    | HASH_PRAGMA elist 
  4267. X        {
  4268. X            hash_pragma(&$2);
  4269. X            el_free(&$2);
  4270. X        }
  4271. X    | error 
  4272. X    ;
  4273. X
  4274. X/*
  4275. X * this expression form is the same as in parse.y
  4276. X * except that the lbrak processing is not necessary.
  4277. X */
  4278. X
  4279. Xexpr
  4280. X    : WORD
  4281. X        {
  4282. X            $$ = expr_alloc();
  4283. X            $$->e_op = OP_WORD;
  4284. X            $$->e_word = $1;
  4285. X            $1 = 0;
  4286. X        }
  4287. X    | LBRAK elist RBRAK
  4288. X        {
  4289. X            $$ = expr_alloc();
  4290. X            $$->e_op = OP_FUNC;
  4291. X            $$->e_list = $2;
  4292. X        }
  4293. X    | expr CATENATE expr
  4294. X        {
  4295. X            $$ = expr_alloc();
  4296. X            $$->e_op = OP_CAT;
  4297. X            $$->e_left = $1;
  4298. X            $$->e_right = $3;
  4299. X        }
  4300. X    ;
  4301. X
  4302. Xelist
  4303. X    : expr
  4304. X        {
  4305. X            el_zero(&$$);
  4306. X            el_append(&$$, $1);
  4307. X            expr_free($1);
  4308. X        }
  4309. X    | elist expr
  4310. X        {
  4311. X            $$ = $1;
  4312. X            el_append(&$$, $2);
  4313. X            expr_free($2);
  4314. X        }
  4315. X    ;
  4316. END_OF_FILE
  4317. if test 12945 -ne `wc -c <'cook/hashline.y'`; then
  4318.     echo shar: \"'cook/hashline.y'\" unpacked with wrong size!
  4319. fi
  4320. # end of 'cook/hashline.y'
  4321. fi
  4322. echo shar: End of archive 6 \(of 11\).
  4323. cp /dev/null ark6isdone
  4324. MISSING=""
  4325. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  4326.     if test ! -f ark${I}isdone ; then
  4327.     MISSING="${MISSING} ${I}"
  4328.     fi
  4329. done
  4330. if test "${MISSING}" = "" ; then
  4331.     echo You have unpacked all 11 archives.
  4332.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  4333. else
  4334.     echo You still need to unpack the following archives:
  4335.     echo "        " ${MISSING}
  4336. fi
  4337. ##  End of shell archive.
  4338. exit 0
  4339.